LCOV - code coverage report
Current view: top level - frmts/mem - memdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1518 1635 92.8 %
Date: 2026-06-19 21:24:00 Functions: 120 128 93.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Memory Array Translator
       4             :  * Purpose:  Complete implementation.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, 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             : #include "memdataset.h"
      16             : #include "memmultidim.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <climits>
      20             : #include <cstdlib>
      21             : #include <cstring>
      22             : #include <limits>
      23             : #include <vector>
      24             : 
      25             : #include "cpl_config.h"
      26             : #include "cpl_conv.h"
      27             : #include "cpl_error.h"
      28             : #include "cpl_minixml.h"
      29             : #include "cpl_progress.h"
      30             : #include "cpl_string.h"
      31             : #include "cpl_vsi.h"
      32             : #include "gdal.h"
      33             : #include "gdal_frmts.h"
      34             : #include "gdal_mem.h"
      35             : 
      36             : struct MEMDataset::Private
      37             : {
      38             :     std::shared_ptr<GDALGroup> m_poRootGroup{};
      39             :     std::map<std::string, std::unique_ptr<GDALRelationship>>
      40             :         m_oMapRelationships{};
      41             : };
      42             : 
      43             : /************************************************************************/
      44             : /*                             MEMCreate()                              */
      45             : /************************************************************************/
      46             : 
      47             : /**
      48             :  * Create a new in-memory raster dataset.
      49             :  *
      50             :  * @param nXSize Width of created raster in pixels.
      51             :  * @param nYSize Height of created raster in pixels.
      52             :  * @param nBands Number of bands.
      53             :  * @param eType Type of raster bands.
      54             :  * @param papszOptions MEM driver creation options.
      55             :  *
      56             :  * @return NULL on failure, or a new MEM dataset handle on success.
      57             :  */
      58             : 
      59           1 : GDALDatasetH MEMCreate(int nXSize, int nYSize, int nBands, GDALDataType eType,
      60             :                        CSLConstList papszOptions)
      61             : 
      62             : {
      63           1 :     return GDALDataset::ToHandle(
      64           1 :         MEMDataset::Create("", nXSize, nYSize, nBands, eType, papszOptions));
      65             : }
      66             : 
      67             : /************************************************************************/
      68             : /*                        MEMCreateRasterBand()                         */
      69             : /************************************************************************/
      70             : 
      71           0 : GDALRasterBandH MEMCreateRasterBand(GDALDataset *poDS, int nBand,
      72             :                                     GByte *pabyData, GDALDataType eType,
      73             :                                     int nPixelOffset, int nLineOffset,
      74             :                                     int bAssumeOwnership)
      75             : 
      76             : {
      77           0 :     return GDALRasterBand::ToHandle(
      78             :         new MEMRasterBand(poDS, nBand, pabyData, eType, nPixelOffset,
      79           0 :                           nLineOffset, bAssumeOwnership));
      80             : }
      81             : 
      82             : /************************************************************************/
      83             : /*                       MEMCreateRasterBandEx()                        */
      84             : /************************************************************************/
      85             : 
      86       35385 : GDALRasterBandH MEMCreateRasterBandEx(GDALDataset *poDS, int nBand,
      87             :                                       GByte *pabyData, GDALDataType eType,
      88             :                                       GSpacing nPixelOffset,
      89             :                                       GSpacing nLineOffset,
      90             :                                       int bAssumeOwnership)
      91             : 
      92             : {
      93       35385 :     return GDALRasterBand::ToHandle(
      94             :         new MEMRasterBand(poDS, nBand, pabyData, eType, nPixelOffset,
      95       70770 :                           nLineOffset, bAssumeOwnership));
      96             : }
      97             : 
      98             : /************************************************************************/
      99             : /*                           MEMRasterBand()                            */
     100             : /************************************************************************/
     101             : 
     102          85 : MEMRasterBand::MEMRasterBand(GByte *pabyDataIn, GDALDataType eTypeIn,
     103          85 :                              int nXSizeIn, int nYSizeIn, bool bOwnDataIn)
     104             :     : GDALPamRasterBand(FALSE), pabyData(pabyDataIn),
     105         170 :       nPixelOffset(GDALGetDataTypeSizeBytes(eTypeIn)), nLineOffset(0),
     106          85 :       bOwnData(bOwnDataIn)
     107             : {
     108          85 :     eAccess = GA_Update;
     109          85 :     eDataType = eTypeIn;
     110          85 :     nRasterXSize = nXSizeIn;
     111          85 :     nRasterYSize = nYSizeIn;
     112          85 :     nBlockXSize = nXSizeIn;
     113          85 :     nBlockYSize = 1;
     114          85 :     nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize);
     115             : 
     116          85 :     PamInitializeNoParent();
     117          85 : }
     118             : 
     119             : /************************************************************************/
     120             : /*                           MEMRasterBand()                            */
     121             : /************************************************************************/
     122             : 
     123      134849 : MEMRasterBand::MEMRasterBand(GDALDataset *poDSIn, int nBandIn,
     124             :                              GByte *pabyDataIn, GDALDataType eTypeIn,
     125             :                              GSpacing nPixelOffsetIn, GSpacing nLineOffsetIn,
     126      134849 :                              int bAssumeOwnership, const char *pszPixelType)
     127             :     : GDALPamRasterBand(FALSE), pabyData(pabyDataIn),
     128             :       nPixelOffset(nPixelOffsetIn), nLineOffset(nLineOffsetIn),
     129      134849 :       bOwnData(bAssumeOwnership)
     130             : {
     131      134849 :     poDS = poDSIn;
     132      134849 :     nBand = nBandIn;
     133             : 
     134      134849 :     eAccess = poDS->GetAccess();
     135             : 
     136      134849 :     eDataType = eTypeIn;
     137             : 
     138      134849 :     nBlockXSize = poDS->GetRasterXSize();
     139      134849 :     nBlockYSize = 1;
     140             : 
     141      134849 :     if (nPixelOffsetIn == 0)
     142      109293 :         nPixelOffset = GDALGetDataTypeSizeBytes(eTypeIn);
     143             : 
     144      134849 :     if (nLineOffsetIn == 0)
     145      111429 :         nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize);
     146             : 
     147      134849 :     if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
     148           0 :         SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", GDAL_MDD_IMAGE_STRUCTURE);
     149             : 
     150      134849 :     PamInitializeNoParent();
     151      134849 : }
     152             : 
     153             : /************************************************************************/
     154             : /*                           ~MEMRasterBand()                           */
     155             : /************************************************************************/
     156             : 
     157      269866 : MEMRasterBand::~MEMRasterBand()
     158             : 
     159             : {
     160      134933 :     if (bOwnData)
     161             :     {
     162       10763 :         VSIFree(pabyData);
     163             :     }
     164      269866 : }
     165             : 
     166             : /************************************************************************/
     167             : /*                             IReadBlock()                             */
     168             : /************************************************************************/
     169             : 
     170       20267 : CPLErr MEMRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     171             :                                  void *pImage)
     172             : {
     173       20267 :     CPLAssert(nBlockXOff == 0);
     174             : 
     175       20267 :     const int nWordSize = GDALGetDataTypeSizeBytes(eDataType);
     176             : 
     177       20267 :     if (nPixelOffset == nWordSize)
     178             :     {
     179       20167 :         memcpy(pImage, pabyData + nLineOffset * static_cast<size_t>(nBlockYOff),
     180       20167 :                static_cast<size_t>(nPixelOffset) * nBlockXSize);
     181             :     }
     182             :     else
     183             :     {
     184         100 :         GByte *const pabyCur =
     185         100 :             pabyData + nLineOffset * static_cast<size_t>(nBlockYOff);
     186             : 
     187       10924 :         for (int iPixel = 0; iPixel < nBlockXSize; iPixel++)
     188             :         {
     189       10824 :             memcpy(static_cast<GByte *>(pImage) + iPixel * nWordSize,
     190       10824 :                    pabyCur + iPixel * nPixelOffset, nWordSize);
     191             :         }
     192             :     }
     193             : 
     194       20267 :     return CE_None;
     195             : }
     196             : 
     197             : /************************************************************************/
     198             : /*                            IWriteBlock()                             */
     199             : /************************************************************************/
     200             : 
     201      121853 : CPLErr MEMRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     202             :                                   void *pImage)
     203             : {
     204      121853 :     CPLAssert(nBlockXOff == 0);
     205      121853 :     const int nWordSize = GDALGetDataTypeSizeBytes(eDataType);
     206             : 
     207      121853 :     if (nPixelOffset == nWordSize)
     208             :     {
     209      121443 :         memcpy(pabyData + nLineOffset * static_cast<size_t>(nBlockYOff), pImage,
     210      121443 :                static_cast<size_t>(nPixelOffset) * nBlockXSize);
     211             :     }
     212             :     else
     213             :     {
     214         410 :         GByte *pabyCur =
     215         410 :             pabyData + nLineOffset * static_cast<size_t>(nBlockYOff);
     216             : 
     217       25910 :         for (int iPixel = 0; iPixel < nBlockXSize; iPixel++)
     218             :         {
     219       25500 :             memcpy(pabyCur + iPixel * nPixelOffset,
     220       25500 :                    static_cast<GByte *>(pImage) + iPixel * nWordSize,
     221             :                    nWordSize);
     222             :         }
     223             :     }
     224             : 
     225      121853 :     return CE_None;
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                             IRasterIO()                              */
     230             : /************************************************************************/
     231             : 
     232     1775990 : CPLErr MEMRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     233             :                                 int nXSize, int nYSize, void *pData,
     234             :                                 int nBufXSize, int nBufYSize,
     235             :                                 GDALDataType eBufType, GSpacing nPixelSpaceBuf,
     236             :                                 GSpacing nLineSpaceBuf,
     237             :                                 GDALRasterIOExtraArg *psExtraArg)
     238             : {
     239     1775990 :     if (nXSize != nBufXSize || nYSize != nBufYSize)
     240             :     {
     241         887 :         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     242             :                                          pData, nBufXSize, nBufYSize, eBufType,
     243             :                                          static_cast<int>(nPixelSpaceBuf),
     244         887 :                                          nLineSpaceBuf, psExtraArg);
     245             :     }
     246             : 
     247             :     // In case block based I/O has been done before.
     248     1775110 :     FlushCache(false);
     249             : 
     250     1775110 :     if (eRWFlag == GF_Read)
     251             :     {
     252     9699120 :         for (int iLine = 0; iLine < nYSize; iLine++)
     253             :         {
     254     8070740 :             GDALCopyWords64(pabyData +
     255     8070740 :                                 nLineOffset *
     256     8070740 :                                     static_cast<GPtrDiff_t>(iLine + nYOff) +
     257     8070740 :                                 nXOff * nPixelOffset,
     258     8070740 :                             eDataType, static_cast<int>(nPixelOffset),
     259             :                             static_cast<GByte *>(pData) +
     260     8070740 :                                 nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine),
     261             :                             eBufType, static_cast<int>(nPixelSpaceBuf), nXSize);
     262             :         }
     263             :     }
     264             :     else
     265             :     {
     266      146728 :         if (nXSize == nRasterXSize && nPixelSpaceBuf == nPixelOffset &&
     267       97970 :             nLineSpaceBuf == nLineOffset)
     268             :         {
     269       97827 :             GDALCopyWords64(pData, eBufType, static_cast<int>(nPixelSpaceBuf),
     270       97827 :                             pabyData +
     271       97827 :                                 nLineOffset * static_cast<GPtrDiff_t>(nYOff),
     272       97827 :                             eDataType, static_cast<int>(nPixelOffset),
     273       97827 :                             static_cast<GPtrDiff_t>(nXSize) * nYSize);
     274             :         }
     275             :         else
     276             :         {
     277      382076 :             for (int iLine = 0; iLine < nYSize; iLine++)
     278             :             {
     279      333175 :                 GDALCopyWords64(
     280      333175 :                     static_cast<GByte *>(pData) +
     281      333175 :                         nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine),
     282             :                     eBufType, static_cast<int>(nPixelSpaceBuf),
     283      333175 :                     pabyData +
     284      333175 :                         nLineOffset * static_cast<GPtrDiff_t>(iLine + nYOff) +
     285      333175 :                         nXOff * nPixelOffset,
     286      333175 :                     eDataType, static_cast<int>(nPixelOffset), nXSize);
     287             :             }
     288             :         }
     289             :     }
     290     1775110 :     return CE_None;
     291             : }
     292             : 
     293             : /************************************************************************/
     294             : /*                             IRasterIO()                              */
     295             : /************************************************************************/
     296             : 
     297      277906 : CPLErr MEMDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     298             :                              int nXSize, int nYSize, void *pData, int nBufXSize,
     299             :                              int nBufYSize, GDALDataType eBufType,
     300             :                              int nBandCount, BANDMAP_TYPE panBandMap,
     301             :                              GSpacing nPixelSpaceBuf, GSpacing nLineSpaceBuf,
     302             :                              GSpacing nBandSpaceBuf,
     303             :                              GDALRasterIOExtraArg *psExtraArg)
     304             : {
     305      277906 :     const int eBufTypeSize = GDALGetDataTypeSizeBytes(eBufType);
     306             : 
     307      883768 :     const auto IsPixelInterleaveDataset = [this, nBandCount, panBandMap]()
     308             :     {
     309      176377 :         GDALDataType eDT = GDT_Unknown;
     310      176377 :         GByte *pabyData = nullptr;
     311      176377 :         GSpacing nPixelOffset = 0;
     312      176377 :         GSpacing nLineOffset = 0;
     313      176377 :         int eDTSize = 0;
     314      177058 :         for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
     315             :         {
     316      176988 :             if (panBandMap[iBandIndex] != iBandIndex + 1)
     317          10 :                 return false;
     318             : 
     319             :             MEMRasterBand *poBand =
     320      176978 :                 cpl::down_cast<MEMRasterBand *>(GetRasterBand(iBandIndex + 1));
     321      176978 :             if (iBandIndex == 0)
     322             :             {
     323      176367 :                 eDT = poBand->GetRasterDataType();
     324      176367 :                 pabyData = poBand->pabyData;
     325      176367 :                 nPixelOffset = poBand->nPixelOffset;
     326      176367 :                 nLineOffset = poBand->nLineOffset;
     327      176367 :                 eDTSize = GDALGetDataTypeSizeBytes(eDT);
     328      176367 :                 if (nPixelOffset != static_cast<GSpacing>(nBands) * eDTSize)
     329      175897 :                     return false;
     330             :             }
     331         611 :             else if (poBand->GetRasterDataType() != eDT ||
     332         611 :                      nPixelOffset != poBand->nPixelOffset ||
     333        1833 :                      nLineOffset != poBand->nLineOffset ||
     334         611 :                      poBand->pabyData != pabyData + iBandIndex * eDTSize)
     335             :             {
     336         400 :                 return false;
     337             :             }
     338             :         }
     339          70 :         return true;
     340      277906 :     };
     341             : 
     342             :     // Detect if we have a pixel-interleaved buffer
     343      277906 :     if (nXSize == nBufXSize && nYSize == nBufYSize && nBandCount == nBands &&
     344      273666 :         nBands > 1 && nBandSpaceBuf == eBufTypeSize &&
     345      171648 :         nPixelSpaceBuf == nBandSpaceBuf * nBands)
     346             :     {
     347       14311 :         const auto IsBandSeparatedDataset = [this, nBandCount, panBandMap]()
     348             :         {
     349        1124 :             GDALDataType eDT = GDT_Unknown;
     350        1124 :             GSpacing nPixelOffset = 0;
     351        1124 :             GSpacing nLineOffset = 0;
     352        1124 :             int eDTSize = 0;
     353        5145 :             for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
     354             :             {
     355        4021 :                 if (panBandMap[iBandIndex] != iBandIndex + 1)
     356           0 :                     return false;
     357             : 
     358        4021 :                 MEMRasterBand *poBand = cpl::down_cast<MEMRasterBand *>(
     359             :                     GetRasterBand(iBandIndex + 1));
     360        4021 :                 if (iBandIndex == 0)
     361             :                 {
     362        1124 :                     eDT = poBand->GetRasterDataType();
     363        1124 :                     nPixelOffset = poBand->nPixelOffset;
     364        1124 :                     nLineOffset = poBand->nLineOffset;
     365        1124 :                     eDTSize = GDALGetDataTypeSizeBytes(eDT);
     366        1124 :                     if (nPixelOffset != eDTSize)
     367           0 :                         return false;
     368             :                 }
     369        2897 :                 else if (poBand->GetRasterDataType() != eDT ||
     370        5794 :                          nPixelOffset != poBand->nPixelOffset ||
     371        2897 :                          nLineOffset != poBand->nLineOffset)
     372             :                 {
     373           0 :                     return false;
     374             :                 }
     375             :             }
     376        1124 :             return true;
     377      170372 :         };
     378             : 
     379      170372 :         if (IsPixelInterleaveDataset())
     380             :         {
     381          11 :             FlushCache(false);
     382             :             const auto poFirstBand =
     383          11 :                 cpl::down_cast<MEMRasterBand *>(papoBands[0]);
     384          11 :             const GDALDataType eDT = poFirstBand->GetRasterDataType();
     385          11 :             GByte *pabyData = poFirstBand->pabyData;
     386          11 :             const GSpacing nPixelOffset = poFirstBand->nPixelOffset;
     387          11 :             const GSpacing nLineOffset = poFirstBand->nLineOffset;
     388          11 :             const int eDTSize = GDALGetDataTypeSizeBytes(eDT);
     389          11 :             if (eRWFlag == GF_Read)
     390             :             {
     391          42 :                 for (int iLine = 0; iLine < nYSize; iLine++)
     392             :                 {
     393          35 :                     GDALCopyWords(
     394             :                         pabyData +
     395          35 :                             nLineOffset * static_cast<size_t>(iLine + nYOff) +
     396          35 :                             nXOff * nPixelOffset,
     397             :                         eDT, eDTSize,
     398             :                         static_cast<GByte *>(pData) +
     399          35 :                             nLineSpaceBuf * static_cast<size_t>(iLine),
     400          35 :                         eBufType, eBufTypeSize, nXSize * nBands);
     401             :                 }
     402             :             }
     403             :             else
     404             :             {
     405          24 :                 for (int iLine = 0; iLine < nYSize; iLine++)
     406             :                 {
     407          20 :                     GDALCopyWords(
     408          20 :                         static_cast<GByte *>(pData) +
     409          20 :                             nLineSpaceBuf * static_cast<size_t>(iLine),
     410             :                         eBufType, eBufTypeSize,
     411             :                         pabyData +
     412          20 :                             nLineOffset * static_cast<size_t>(iLine + nYOff) +
     413          20 :                             nXOff * nPixelOffset,
     414          20 :                         eDT, eDTSize, nXSize * nBands);
     415             :                 }
     416             :             }
     417        1135 :             return CE_None;
     418             :         }
     419      171485 :         else if (eRWFlag == GF_Write && nBandCount <= 4 &&
     420        1124 :                  IsBandSeparatedDataset())
     421             :         {
     422             :             // TODO: once we have a GDALInterleave() function, implement the
     423             :             // GF_Read case
     424        1124 :             FlushCache(false);
     425             :             const auto poFirstBand =
     426        1124 :                 cpl::down_cast<MEMRasterBand *>(papoBands[0]);
     427        1124 :             const GDALDataType eDT = poFirstBand->GetRasterDataType();
     428        1124 :             void *ppDestBuffer[4] = {nullptr, nullptr, nullptr, nullptr};
     429        1124 :             if (nXOff == 0 && nXSize == nRasterXSize &&
     430        1116 :                 poFirstBand->nLineOffset ==
     431        1116 :                     poFirstBand->nPixelOffset * nXSize &&
     432        1116 :                 nLineSpaceBuf == nPixelSpaceBuf * nXSize)
     433             :             {
     434             :                 // Optimization of the general case in the below else() clause:
     435             :                 // writing whole strips from a fully packed buffer
     436        5113 :                 for (int i = 0; i < nBandCount; ++i)
     437             :                 {
     438             :                     const auto poBand =
     439        3997 :                         cpl::down_cast<MEMRasterBand *>(papoBands[i]);
     440        3997 :                     ppDestBuffer[i] =
     441        3997 :                         poBand->pabyData + poBand->nLineOffset * nYOff;
     442             :                 }
     443        1116 :                 GDALDeinterleave(pData, eBufType, nBandCount, ppDestBuffer, eDT,
     444        1116 :                                  static_cast<size_t>(nXSize) * nYSize);
     445             :             }
     446             :             else
     447             :             {
     448         103 :                 for (int iLine = 0; iLine < nYSize; iLine++)
     449             :                 {
     450         380 :                     for (int i = 0; i < nBandCount; ++i)
     451             :                     {
     452             :                         const auto poBand =
     453         285 :                             cpl::down_cast<MEMRasterBand *>(papoBands[i]);
     454         285 :                         ppDestBuffer[i] = poBand->pabyData +
     455         285 :                                           poBand->nPixelOffset * nXOff +
     456         285 :                                           poBand->nLineOffset * (iLine + nYOff);
     457             :                     }
     458          95 :                     GDALDeinterleave(
     459          95 :                         static_cast<GByte *>(pData) +
     460          95 :                             nLineSpaceBuf * static_cast<size_t>(iLine),
     461             :                         eBufType, nBandCount, ppDestBuffer, eDT, nXSize);
     462             :                 }
     463             :             }
     464        1124 :             return CE_None;
     465      169237 :         }
     466             :     }
     467             :     // From a band-interleaved buffer to a pixel-interleaved dataset
     468        8207 :     else if (eRWFlag == GF_Write && nXSize == nBufXSize &&
     469        8206 :              nYSize == nBufYSize && nXSize == nRasterXSize &&
     470        8101 :              nBandCount == nBands && nBands > 1 &&
     471        6009 :              nPixelSpaceBuf == eBufTypeSize &&
     472        6007 :              nLineSpaceBuf == nPixelSpaceBuf * nBufXSize &&
     473      121746 :              nBandSpaceBuf == nLineSpaceBuf * nBufYSize &&
     474        6005 :              IsPixelInterleaveDataset())
     475             :     {
     476          59 :         FlushCache(false);
     477             : 
     478          59 :         auto poDstBand = cpl::down_cast<MEMRasterBand *>(papoBands[0]);
     479         118 :         GDALTranspose2D(pData, eBufType,
     480          59 :                         poDstBand->pabyData + nYOff * poDstBand->nLineOffset,
     481             :                         poDstBand->GetRasterDataType(),
     482          59 :                         static_cast<size_t>(nXSize) * nYSize, nBands);
     483          59 :         return CE_None;
     484             :     }
     485             : 
     486      276712 :     if (nBufXSize != nXSize || nBufYSize != nYSize)
     487         377 :         return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     488             :                                       pData, nBufXSize, nBufYSize, eBufType,
     489             :                                       nBandCount, panBandMap, nPixelSpaceBuf,
     490         377 :                                       nLineSpaceBuf, nBandSpaceBuf, psExtraArg);
     491             : 
     492      276335 :     return GDALDataset::BandBasedRasterIO(
     493             :         eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     494             :         eBufType, nBandCount, panBandMap, nPixelSpaceBuf, nLineSpaceBuf,
     495      276335 :         nBandSpaceBuf, psExtraArg);
     496             : }
     497             : 
     498             : /************************************************************************/
     499             : /*                          GetOverviewCount()                          */
     500             : /************************************************************************/
     501             : 
     502       10491 : int MEMRasterBand::GetOverviewCount()
     503             : {
     504       10491 :     MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
     505       10491 :     if (poMemDS == nullptr)
     506          12 :         return 0;
     507       10479 :     return static_cast<int>(poMemDS->m_apoOverviewDS.size());
     508             : }
     509             : 
     510             : /************************************************************************/
     511             : /*                            GetOverview()                             */
     512             : /************************************************************************/
     513             : 
     514       61466 : GDALRasterBand *MEMRasterBand::GetOverview(int i)
     515             : 
     516             : {
     517       61466 :     MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
     518       61466 :     if (poMemDS == nullptr)
     519           0 :         return nullptr;
     520       61466 :     if (i < 0 || i >= static_cast<int>(poMemDS->m_apoOverviewDS.size()))
     521          17 :         return nullptr;
     522       61449 :     return poMemDS->m_apoOverviewDS[i]->GetRasterBand(nBand);
     523             : }
     524             : 
     525             : /************************************************************************/
     526             : /*                           CreateMaskBand()                           */
     527             : /************************************************************************/
     528             : 
     529          84 : CPLErr MEMRasterBand::CreateMaskBand(int nFlagsIn)
     530             : {
     531          84 :     InvalidateMaskBand();
     532             : 
     533          84 :     MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
     534          84 :     if ((nFlagsIn & GMF_PER_DATASET) != 0 && nBand != 1 && poMemDS != nullptr)
     535             :     {
     536             :         MEMRasterBand *poFirstBand =
     537           1 :             dynamic_cast<MEMRasterBand *>(poMemDS->GetRasterBand(1));
     538           1 :         if (poFirstBand != nullptr)
     539           1 :             return poFirstBand->CreateMaskBand(nFlagsIn);
     540             :     }
     541             : 
     542             :     GByte *pabyMaskData =
     543          83 :         static_cast<GByte *>(VSI_CALLOC_VERBOSE(nRasterXSize, nRasterYSize));
     544          83 :     if (pabyMaskData == nullptr)
     545           0 :         return CE_Failure;
     546             : 
     547          83 :     nMaskFlags = nFlagsIn;
     548             :     auto poMemMaskBand = std::unique_ptr<MEMRasterBand>(
     549             :         new MEMRasterBand(pabyMaskData, GDT_UInt8, nRasterXSize, nRasterYSize,
     550          83 :                           /* bOwnData= */ true));
     551          83 :     poMemMaskBand->m_bIsMask = true;
     552          83 :     poMask.reset(std::move(poMemMaskBand));
     553          83 :     if ((nFlagsIn & GMF_PER_DATASET) != 0 && nBand == 1 && poMemDS != nullptr)
     554             :     {
     555          87 :         for (int i = 2; i <= poMemDS->GetRasterCount(); ++i)
     556             :         {
     557             :             MEMRasterBand *poOtherBand =
     558          14 :                 cpl::down_cast<MEMRasterBand *>(poMemDS->GetRasterBand(i));
     559          14 :             poOtherBand->InvalidateMaskBand();
     560          14 :             poOtherBand->nMaskFlags = nFlagsIn;
     561          14 :             poOtherBand->poMask.resetNotOwned(poMask.get());
     562             :         }
     563             :     }
     564          83 :     return CE_None;
     565             : }
     566             : 
     567             : /************************************************************************/
     568             : /*                             IsMaskBand()                             */
     569             : /************************************************************************/
     570             : 
     571         222 : bool MEMRasterBand::IsMaskBand() const
     572             : {
     573         222 :     return m_bIsMask || GDALPamRasterBand::IsMaskBand();
     574             : }
     575             : 
     576             : /************************************************************************/
     577             : /* ==================================================================== */
     578             : /*      MEMDataset                                                     */
     579             : /* ==================================================================== */
     580             : /************************************************************************/
     581             : 
     582             : /************************************************************************/
     583             : /*                             MEMDataset()                             */
     584             : /************************************************************************/
     585             : 
     586       35966 : MEMDataset::MEMDataset()
     587       35966 :     : GDALDataset(FALSE), bGeoTransformSet(FALSE), m_poPrivate(new Private())
     588             : {
     589       35966 :     m_gt.yscale = -1;
     590       35966 :     DisableReadWriteMutex();
     591       35966 : }
     592             : 
     593             : /************************************************************************/
     594             : /*                            ~MEMDataset()                             */
     595             : /************************************************************************/
     596             : 
     597       71920 : MEMDataset::~MEMDataset()
     598             : 
     599             : {
     600       35960 :     MEMDataset::Close();
     601       71920 : }
     602             : 
     603             : /************************************************************************/
     604             : /*                               Close()                                */
     605             : /************************************************************************/
     606             : 
     607       63223 : CPLErr MEMDataset::Close(GDALProgressFunc, void *)
     608             : {
     609       63223 :     CPLErr eErr = CE_None;
     610       63223 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     611             :     {
     612       35960 :         const bool bSuppressOnCloseBackup = bSuppressOnClose;
     613       35960 :         bSuppressOnClose = true;
     614       35960 :         FlushCache(true);
     615      170773 :         for (int i = 0; i < nBands; ++i)
     616             :         {
     617      134813 :             auto poMEMBand = dynamic_cast<MEMRasterBand *>(papoBands[i]);
     618      134813 :             if (poMEMBand && poMEMBand->poMask)
     619       84582 :                 poMEMBand->poMask.get()->FlushCache(true);
     620             :         }
     621       35960 :         bSuppressOnClose = bSuppressOnCloseBackup;
     622       35960 :         m_apoOverviewDS.clear();
     623       35960 :         eErr = GDALDataset::Close();
     624             :     }
     625             : 
     626       63223 :     return eErr;
     627             : }
     628             : 
     629             : #if 0
     630             : /************************************************************************/
     631             : /*                           EnterReadWrite()                           */
     632             : /************************************************************************/
     633             : 
     634             : int MEMDataset::EnterReadWrite(CPL_UNUSED GDALRWFlag eRWFlag)
     635             : {
     636             :     return TRUE;
     637             : }
     638             : 
     639             : /************************************************************************/
     640             : /*                           LeaveReadWrite()                           */
     641             : /************************************************************************/
     642             : 
     643             : void MEMDataset::LeaveReadWrite()
     644             : {
     645             : }
     646             : #endif  // if 0
     647             : 
     648             : /************************************************************************/
     649             : /*                           GetSpatialRef()                            */
     650             : /************************************************************************/
     651             : 
     652       12897 : const OGRSpatialReference *MEMDataset::GetSpatialRef() const
     653             : 
     654             : {
     655       12897 :     if (GetLayerCount())
     656           7 :         return GDALDataset::GetSpatialRef();
     657       12890 :     return GetSpatialRefRasterOnly();
     658             : }
     659             : 
     660             : /************************************************************************/
     661             : /*                      GetSpatialRefRasterOnly()                       */
     662             : /************************************************************************/
     663             : 
     664       13610 : const OGRSpatialReference *MEMDataset::GetSpatialRefRasterOnly() const
     665             : 
     666             : {
     667       13610 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     668             : }
     669             : 
     670             : /************************************************************************/
     671             : /*                           SetSpatialRef()                            */
     672             : /************************************************************************/
     673             : 
     674        1947 : CPLErr MEMDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
     675             : 
     676             : {
     677        1947 :     m_oSRS.Clear();
     678        1947 :     if (poSRS)
     679        1875 :         m_oSRS = *poSRS;
     680             : 
     681        1947 :     return CE_None;
     682             : }
     683             : 
     684             : /************************************************************************/
     685             : /*                          GetGeoTransform()                           */
     686             : /************************************************************************/
     687             : 
     688       13920 : CPLErr MEMDataset::GetGeoTransform(GDALGeoTransform &gt) const
     689             : 
     690             : {
     691       13920 :     gt = m_gt;
     692       13920 :     if (bGeoTransformSet)
     693        7604 :         return CE_None;
     694             : 
     695        6316 :     return CE_Failure;
     696             : }
     697             : 
     698             : /************************************************************************/
     699             : /*                          SetGeoTransform()                           */
     700             : /************************************************************************/
     701             : 
     702        3142 : CPLErr MEMDataset::SetGeoTransform(const GDALGeoTransform &gt)
     703             : 
     704             : {
     705        3142 :     m_gt = gt;
     706        3142 :     bGeoTransformSet = TRUE;
     707             : 
     708        3142 :     return CE_None;
     709             : }
     710             : 
     711             : /************************************************************************/
     712             : /*                         GetInternalHandle()                          */
     713             : /************************************************************************/
     714             : 
     715         520 : void *MEMDataset::GetInternalHandle(const char *pszRequest)
     716             : 
     717             : {
     718             :     // check for MEMORYnnn string in pszRequest (nnnn can be up to 10
     719             :     // digits, or even omitted)
     720         520 :     if (STARTS_WITH_CI(pszRequest, "MEMORY"))
     721             :     {
     722         437 :         if (int BandNumber = static_cast<int>(CPLScanLong(&pszRequest[6], 10)))
     723             :         {
     724             :             MEMRasterBand *RequestedRasterBand =
     725         437 :                 cpl::down_cast<MEMRasterBand *>(GetRasterBand(BandNumber));
     726             : 
     727             :             // we're within a MEMDataset so the only thing a RasterBand
     728             :             // could be is a MEMRasterBand
     729             : 
     730         437 :             if (RequestedRasterBand != nullptr)
     731             :             {
     732             :                 // return the internal band data pointer
     733         437 :                 return RequestedRasterBand->GetData();
     734             :             }
     735             :         }
     736             :     }
     737             : 
     738          83 :     return nullptr;
     739             : }
     740             : 
     741             : /************************************************************************/
     742             : /*                            GetGCPCount()                             */
     743             : /************************************************************************/
     744             : 
     745        7463 : int MEMDataset::GetGCPCount()
     746             : 
     747             : {
     748        7463 :     return static_cast<int>(m_aoGCPs.size());
     749             : }
     750             : 
     751             : /************************************************************************/
     752             : /*                          GetGCPSpatialRef()                          */
     753             : /************************************************************************/
     754             : 
     755         458 : const OGRSpatialReference *MEMDataset::GetGCPSpatialRef() const
     756             : 
     757             : {
     758         458 :     return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
     759             : }
     760             : 
     761             : /************************************************************************/
     762             : /*                              GetGCPs()                               */
     763             : /************************************************************************/
     764             : 
     765          64 : const GDAL_GCP *MEMDataset::GetGCPs()
     766             : 
     767             : {
     768          64 :     return gdal::GCP::c_ptr(m_aoGCPs);
     769             : }
     770             : 
     771             : /************************************************************************/
     772             : /*                              SetGCPs()                               */
     773             : /************************************************************************/
     774             : 
     775          11 : CPLErr MEMDataset::SetGCPs(int nNewCount, const GDAL_GCP *pasNewGCPList,
     776             :                            const OGRSpatialReference *poSRS)
     777             : 
     778             : {
     779          11 :     m_oGCPSRS.Clear();
     780          11 :     if (poSRS)
     781           6 :         m_oGCPSRS = *poSRS;
     782             : 
     783          11 :     m_aoGCPs = gdal::GCP::fromC(pasNewGCPList, nNewCount);
     784             : 
     785          11 :     return CE_None;
     786             : }
     787             : 
     788             : /************************************************************************/
     789             : /*                              AddBand()                               */
     790             : /*                                                                      */
     791             : /*      Add a new band to the dataset, allowing creation options to     */
     792             : /*      specify the existing memory to use, otherwise create new        */
     793             : /*      memory.                                                         */
     794             : /************************************************************************/
     795             : 
     796         913 : CPLErr MEMDataset::AddBand(GDALDataType eType, CSLConstList papszOptions)
     797             : 
     798             : {
     799         913 :     const int nBandId = GetRasterCount() + 1;
     800         913 :     const GSpacing nPixelSize = GDALGetDataTypeSizeBytes(eType);
     801         913 :     if (nPixelSize == 0)
     802             :     {
     803           1 :         ReportError(CE_Failure, CPLE_IllegalArg,
     804             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
     805           1 :         return CE_Failure;
     806             :     }
     807             : 
     808             :     /* -------------------------------------------------------------------- */
     809             :     /*      Do we need to allocate the memory ourselves?  This is the       */
     810             :     /*      simple case.                                                    */
     811             :     /* -------------------------------------------------------------------- */
     812        1824 :     const CPLStringList aosOptions(papszOptions);
     813         912 :     if (aosOptions.FetchNameValue("DATAPOINTER") == nullptr)
     814             :     {
     815         276 :         const GSpacing nTmp = nPixelSize * GetRasterXSize();
     816             :         GByte *pData =
     817             : #if SIZEOF_VOIDP == 4
     818             :             (nTmp > INT_MAX) ? nullptr :
     819             : #endif
     820         276 :                              static_cast<GByte *>(VSI_CALLOC_VERBOSE(
     821             :                                  static_cast<size_t>(nTmp), GetRasterYSize()));
     822             : 
     823         276 :         if (pData == nullptr)
     824             :         {
     825           1 :             return CE_Failure;
     826             :         }
     827             : 
     828         275 :         SetBand(nBandId,
     829             :                 new MEMRasterBand(this, nBandId, pData, eType, nPixelSize,
     830         275 :                                   nPixelSize * GetRasterXSize(), TRUE));
     831             : 
     832         275 :         return CE_None;
     833             :     }
     834             : 
     835             :     /* -------------------------------------------------------------------- */
     836             :     /*      Get layout of memory and other flags.                           */
     837             :     /* -------------------------------------------------------------------- */
     838         636 :     const char *pszDataPointer = aosOptions.FetchNameValue("DATAPOINTER");
     839        1272 :     GByte *pData = static_cast<GByte *>(CPLScanPointer(
     840         636 :         pszDataPointer, static_cast<int>(strlen(pszDataPointer))));
     841             : 
     842         636 :     const char *pszOption = aosOptions.FetchNameValue("PIXELOFFSET");
     843             :     GSpacing nPixelOffset;
     844         636 :     if (pszOption == nullptr)
     845         636 :         nPixelOffset = nPixelSize;
     846             :     else
     847           0 :         nPixelOffset = CPLAtoGIntBig(pszOption);
     848             : 
     849         636 :     pszOption = aosOptions.FetchNameValue("LINEOFFSET");
     850             :     GSpacing nLineOffset;
     851         636 :     if (pszOption == nullptr)
     852         636 :         nLineOffset = GetRasterXSize() * static_cast<size_t>(nPixelOffset);
     853             :     else
     854           0 :         nLineOffset = CPLAtoGIntBig(pszOption);
     855             : 
     856         636 :     SetBand(nBandId, new MEMRasterBand(this, nBandId, pData, eType,
     857         636 :                                        nPixelOffset, nLineOffset, FALSE));
     858             : 
     859         636 :     return CE_None;
     860             : }
     861             : 
     862             : /************************************************************************/
     863             : /*                             AddMEMBand()                             */
     864             : /************************************************************************/
     865             : 
     866       13140 : void MEMDataset::AddMEMBand(GDALRasterBandH hMEMBand)
     867             : {
     868       13140 :     auto poBand = GDALRasterBand::FromHandle(hMEMBand);
     869       13140 :     CPLAssert(dynamic_cast<MEMRasterBand *>(poBand) != nullptr);
     870       13140 :     SetBand(1 + nBands, poBand);
     871       13140 : }
     872             : 
     873             : /************************************************************************/
     874             : /*                          IBuildOverviews()                           */
     875             : /************************************************************************/
     876             : 
     877         187 : CPLErr MEMDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
     878             :                                    const int *panOverviewList, int nListBands,
     879             :                                    const int *panBandList,
     880             :                                    GDALProgressFunc pfnProgress,
     881             :                                    void *pProgressData,
     882             :                                    CSLConstList papszOptions)
     883             : {
     884         187 :     if (nBands == 0)
     885             :     {
     886           1 :         CPLError(CE_Failure, CPLE_NotSupported, "Dataset has zero bands.");
     887           1 :         return CE_Failure;
     888             :     }
     889             : 
     890         186 :     if (nListBands != nBands)
     891             :     {
     892           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     893             :                  "Generation of overviews in MEM only"
     894             :                  "supported when operating on all bands.");
     895           0 :         return CE_Failure;
     896             :     }
     897             : 
     898         186 :     if (nOverviews == 0)
     899             :     {
     900             :         // Cleanup existing overviews
     901           2 :         m_apoOverviewDS.clear();
     902           2 :         return CE_None;
     903             :     }
     904             : 
     905             :     /* -------------------------------------------------------------------- */
     906             :     /*      Force cascading. Help to get accurate results when masks are    */
     907             :     /*      involved.                                                       */
     908             :     /* -------------------------------------------------------------------- */
     909         184 :     if (nOverviews > 1 &&
     910          24 :         (STARTS_WITH_CI(pszResampling, "AVER") ||
     911          22 :          STARTS_WITH_CI(pszResampling, "GAUSS") ||
     912          22 :          EQUAL(pszResampling, "CUBIC") || EQUAL(pszResampling, "CUBICSPLINE") ||
     913          22 :          EQUAL(pszResampling, "LANCZOS") || EQUAL(pszResampling, "BILINEAR")))
     914             :     {
     915           7 :         double dfTotalPixels = 0;
     916          21 :         for (int i = 0; i < nOverviews; i++)
     917             :         {
     918          14 :             dfTotalPixels += static_cast<double>(nRasterXSize) * nRasterYSize /
     919          14 :                              (panOverviewList[i] * panOverviewList[i]);
     920             :         }
     921             : 
     922           7 :         double dfAccPixels = 0;
     923          21 :         for (int i = 0; i < nOverviews; i++)
     924             :         {
     925          14 :             double dfPixels = static_cast<double>(nRasterXSize) * nRasterYSize /
     926          14 :                               (panOverviewList[i] * panOverviewList[i]);
     927          28 :             void *pScaledProgress = GDALCreateScaledProgress(
     928             :                 dfAccPixels / dfTotalPixels,
     929          14 :                 (dfAccPixels + dfPixels) / dfTotalPixels, pfnProgress,
     930             :                 pProgressData);
     931          28 :             CPLErr eErr = IBuildOverviews(
     932          14 :                 pszResampling, 1, &panOverviewList[i], nListBands, panBandList,
     933          14 :                 GDALScaledProgress, pScaledProgress, papszOptions);
     934          14 :             GDALDestroyScaledProgress(pScaledProgress);
     935          14 :             dfAccPixels += dfPixels;
     936          14 :             if (eErr == CE_Failure)
     937           0 :                 return eErr;
     938             :         }
     939           7 :         return CE_None;
     940             :     }
     941             : 
     942             :     /* -------------------------------------------------------------------- */
     943             :     /*      Establish which of the overview levels we already have, and     */
     944             :     /*      which are new.                                                  */
     945             :     /* -------------------------------------------------------------------- */
     946         177 :     GDALRasterBand *poBand = GetRasterBand(1);
     947             : 
     948         375 :     for (int i = 0; i < nOverviews; i++)
     949             :     {
     950         198 :         bool bExisting = false;
     951         233 :         for (int j = 0; j < poBand->GetOverviewCount(); j++)
     952             :         {
     953          43 :             GDALRasterBand *poOverview = poBand->GetOverview(j);
     954          43 :             if (poOverview == nullptr)
     955           0 :                 continue;
     956             : 
     957             :             int nOvFactor =
     958          43 :                 GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
     959             :                                     poOverview->GetYSize(), poBand->GetYSize());
     960             : 
     961          78 :             if (nOvFactor == panOverviewList[i] ||
     962          35 :                 nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
     963             :                                                 poBand->GetXSize(),
     964             :                                                 poBand->GetYSize()))
     965             :             {
     966           8 :                 bExisting = true;
     967           8 :                 break;
     968             :             }
     969             :         }
     970             : 
     971             :         // Create new overview dataset if needed.
     972         198 :         if (!bExisting)
     973             :         {
     974         190 :             auto poOvrDS = std::make_unique<MEMDataset>();
     975         190 :             poOvrDS->eAccess = GA_Update;
     976         190 :             poOvrDS->nRasterXSize =
     977         190 :                 DIV_ROUND_UP(nRasterXSize, panOverviewList[i]);
     978         190 :             poOvrDS->nRasterYSize =
     979         190 :                 DIV_ROUND_UP(nRasterYSize, panOverviewList[i]);
     980         190 :             poOvrDS->bGeoTransformSet = bGeoTransformSet;
     981         190 :             poOvrDS->m_gt = m_gt;
     982             :             const double dfOvrXRatio =
     983         190 :                 static_cast<double>(nRasterXSize) / poOvrDS->nRasterXSize;
     984             :             const double dfOvrYRatio =
     985         190 :                 static_cast<double>(nRasterYSize) / poOvrDS->nRasterYSize;
     986         190 :             poOvrDS->m_gt.Rescale(dfOvrXRatio, dfOvrYRatio);
     987         190 :             poOvrDS->m_oSRS = m_oSRS;
     988         452 :             for (int iBand = 0; iBand < nBands; iBand++)
     989             :             {
     990             :                 const GDALDataType eDT =
     991         262 :                     GetRasterBand(iBand + 1)->GetRasterDataType();
     992         262 :                 if (poOvrDS->AddBand(eDT, nullptr) != CE_None)
     993             :                 {
     994           0 :                     return CE_Failure;
     995             :                 }
     996             :             }
     997         190 :             m_apoOverviewDS.emplace_back(poOvrDS.release());
     998             :         }
     999             :     }
    1000             : 
    1001             :     /* -------------------------------------------------------------------- */
    1002             :     /*      Build band list.                                                */
    1003             :     /* -------------------------------------------------------------------- */
    1004             :     GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
    1005         177 :         CPLCalloc(sizeof(GDALRasterBand *), nBands));
    1006         412 :     for (int i = 0; i < nBands; i++)
    1007         235 :         pahBands[i] = GetRasterBand(panBandList[i]);
    1008             : 
    1009             :     /* -------------------------------------------------------------------- */
    1010             :     /*      Refresh overviews that were listed.                             */
    1011             :     /* -------------------------------------------------------------------- */
    1012             :     GDALRasterBand **papoOverviewBands =
    1013         177 :         static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
    1014             :     GDALRasterBand **papoMaskOverviewBands =
    1015         177 :         static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
    1016             : 
    1017         177 :     CPLErr eErr = CE_None;
    1018         412 :     for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
    1019             :     {
    1020         235 :         poBand = GetRasterBand(panBandList[iBand]);
    1021             : 
    1022         235 :         int nNewOverviews = 0;
    1023         505 :         for (int i = 0; i < nOverviews; i++)
    1024             :         {
    1025         320 :             for (int j = 0; j < poBand->GetOverviewCount(); j++)
    1026             :             {
    1027         320 :                 GDALRasterBand *poOverview = poBand->GetOverview(j);
    1028             : 
    1029         320 :                 int bHasNoData = FALSE;
    1030         320 :                 double noDataValue = poBand->GetNoDataValue(&bHasNoData);
    1031             : 
    1032         320 :                 if (bHasNoData)
    1033          78 :                     poOverview->SetNoDataValue(noDataValue);
    1034             : 
    1035         320 :                 const int nOvFactor = GDALComputeOvFactor(
    1036             :                     poOverview->GetXSize(), poBand->GetXSize(),
    1037             :                     poOverview->GetYSize(), poBand->GetYSize());
    1038             : 
    1039         370 :                 if (nOvFactor == panOverviewList[i] ||
    1040          50 :                     nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    1041             :                                                     poBand->GetXSize(),
    1042             :                                                     poBand->GetYSize()))
    1043             :                 {
    1044         270 :                     papoOverviewBands[nNewOverviews++] = poOverview;
    1045         270 :                     break;
    1046             :                 }
    1047             :             }
    1048             :         }
    1049             : 
    1050             :         // If the band has an explicit mask, we need to create overviews
    1051             :         // for it
    1052         235 :         MEMRasterBand *poMEMBand = cpl::down_cast<MEMRasterBand *>(poBand);
    1053             :         const bool bMustGenerateMaskOvr =
    1054         295 :             ((poMEMBand->poMask != nullptr && poMEMBand->poMask.IsOwned()) ||
    1055             :              // Or if it is a per-dataset mask, in which case just do it for the
    1056             :              // first band
    1057         296 :              ((poMEMBand->nMaskFlags & GMF_PER_DATASET) != 0 && iBand == 0)) &&
    1058          59 :             dynamic_cast<MEMRasterBand *>(poBand->GetMaskBand()) != nullptr;
    1059             : 
    1060         235 :         if (nNewOverviews > 0 && bMustGenerateMaskOvr)
    1061             :         {
    1062          12 :             for (int i = 0; i < nNewOverviews; i++)
    1063             :             {
    1064             :                 MEMRasterBand *poMEMOvrBand =
    1065           7 :                     cpl::down_cast<MEMRasterBand *>(papoOverviewBands[i]);
    1066           7 :                 if (!(poMEMOvrBand->poMask != nullptr &&
    1067          14 :                       poMEMOvrBand->poMask.IsOwned()) &&
    1068           7 :                     (poMEMOvrBand->nMaskFlags & GMF_PER_DATASET) == 0)
    1069             :                 {
    1070           7 :                     poMEMOvrBand->CreateMaskBand(poMEMBand->nMaskFlags);
    1071             :                 }
    1072           7 :                 papoMaskOverviewBands[i] = poMEMOvrBand->GetMaskBand();
    1073             :             }
    1074             : 
    1075          10 :             void *pScaledProgress = GDALCreateScaledProgress(
    1076           5 :                 1.0 * iBand / nBands, 1.0 * (iBand + 0.5) / nBands, pfnProgress,
    1077             :                 pProgressData);
    1078             : 
    1079             :             MEMRasterBand *poMaskBand =
    1080           5 :                 cpl::down_cast<MEMRasterBand *>(poBand->GetMaskBand());
    1081             :             // Make the mask band to be its own mask, similarly to what is
    1082             :             // done for alpha bands in GDALRegenerateOverviews() (#5640)
    1083           5 :             poMaskBand->InvalidateMaskBand();
    1084           5 :             poMaskBand->poMask.resetNotOwned(poMaskBand);
    1085           5 :             poMaskBand->nMaskFlags = 0;
    1086           5 :             eErr = GDALRegenerateOverviewsEx(
    1087             :                 GDALRasterBand::ToHandle(poMaskBand), nNewOverviews,
    1088             :                 reinterpret_cast<GDALRasterBandH *>(papoMaskOverviewBands),
    1089             :                 pszResampling, GDALScaledProgress, pScaledProgress,
    1090             :                 papszOptions);
    1091           5 :             poMaskBand->InvalidateMaskBand();
    1092           5 :             GDALDestroyScaledProgress(pScaledProgress);
    1093             :         }
    1094             : 
    1095             :         // Generate overview of bands *AFTER* mask overviews
    1096         235 :         if (nNewOverviews > 0 && eErr == CE_None)
    1097             :         {
    1098         705 :             void *pScaledProgress = GDALCreateScaledProgress(
    1099         235 :                 1.0 * (iBand + (bMustGenerateMaskOvr ? 0.5 : 1)) / nBands,
    1100         235 :                 1.0 * (iBand + 1) / nBands, pfnProgress, pProgressData);
    1101         235 :             eErr = GDALRegenerateOverviewsEx(
    1102             :                 GDALRasterBand::ToHandle(poBand), nNewOverviews,
    1103             :                 reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
    1104             :                 pszResampling, GDALScaledProgress, pScaledProgress,
    1105             :                 papszOptions);
    1106         235 :             GDALDestroyScaledProgress(pScaledProgress);
    1107             :         }
    1108             :     }
    1109             : 
    1110             :     /* -------------------------------------------------------------------- */
    1111             :     /*      Cleanup                                                         */
    1112             :     /* -------------------------------------------------------------------- */
    1113         177 :     CPLFree(papoOverviewBands);
    1114         177 :     CPLFree(papoMaskOverviewBands);
    1115         177 :     CPLFree(pahBands);
    1116             : 
    1117         177 :     return eErr;
    1118             : }
    1119             : 
    1120             : /************************************************************************/
    1121             : /*                           CreateMaskBand()                           */
    1122             : /************************************************************************/
    1123             : 
    1124          65 : CPLErr MEMDataset::CreateMaskBand(int nFlagsIn)
    1125             : {
    1126          65 :     GDALRasterBand *poFirstBand = GetRasterBand(1);
    1127          65 :     if (poFirstBand == nullptr)
    1128           1 :         return CE_Failure;
    1129          64 :     return poFirstBand->CreateMaskBand(nFlagsIn | GMF_PER_DATASET);
    1130             : }
    1131             : 
    1132             : /************************************************************************/
    1133             : /*                            CanBeCloned()                             */
    1134             : /************************************************************************/
    1135             : 
    1136             : /** Implements GDALDataset::CanBeCloned()
    1137             :  *
    1138             :  * This method is called by GDALThreadSafeDataset::Create() to determine if
    1139             :  * it is possible to create a thread-safe wrapper for a dataset, which involves
    1140             :  * the ability to Clone() it.
    1141             :  *
    1142             :  * The implementation of this method must be thread-safe.
    1143             :  */
    1144          51 : bool MEMDataset::CanBeCloned(int nScopeFlags, bool bCanShareState) const
    1145             : {
    1146         102 :     return nScopeFlags == GDAL_OF_RASTER && bCanShareState &&
    1147         102 :            typeid(this) == typeid(const MEMDataset *);
    1148             : }
    1149             : 
    1150             : /************************************************************************/
    1151             : /*                               Clone()                                */
    1152             : /************************************************************************/
    1153             : 
    1154             : /** Implements GDALDataset::Clone()
    1155             :  *
    1156             :  * This method returns a new instance, identical to "this", but which shares the
    1157             :  * same memory buffer as "this".
    1158             :  *
    1159             :  * The implementation of this method must be thread-safe.
    1160             :  */
    1161          16 : std::unique_ptr<GDALDataset> MEMDataset::Clone(int nScopeFlags,
    1162             :                                                bool bCanShareState) const
    1163             : {
    1164          16 :     if (MEMDataset::CanBeCloned(nScopeFlags, bCanShareState))
    1165             :     {
    1166          32 :         auto poNewDS = std::make_unique<MEMDataset>();
    1167          16 :         poNewDS->poDriver = poDriver;
    1168          16 :         poNewDS->nRasterXSize = nRasterXSize;
    1169          16 :         poNewDS->nRasterYSize = nRasterYSize;
    1170          16 :         poNewDS->bGeoTransformSet = bGeoTransformSet;
    1171          16 :         poNewDS->m_gt = m_gt;
    1172          16 :         poNewDS->m_oSRS = m_oSRS;
    1173          16 :         poNewDS->m_aoGCPs = m_aoGCPs;
    1174          16 :         poNewDS->m_oGCPSRS = m_oGCPSRS;
    1175          22 :         for (const auto &poOvrDS : m_apoOverviewDS)
    1176             :         {
    1177           6 :             poNewDS->m_apoOverviewDS.emplace_back(
    1178           6 :                 poOvrDS->Clone(nScopeFlags, bCanShareState).release());
    1179             :         }
    1180             : 
    1181          16 :         poNewDS->SetDescription(GetDescription());
    1182          16 :         poNewDS->oMDMD = oMDMD;
    1183             : 
    1184             :         // Clone bands
    1185          38 :         for (int i = 1; i <= nBands; ++i)
    1186             :         {
    1187             :             auto poSrcMEMBand =
    1188          22 :                 dynamic_cast<const MEMRasterBand *>(papoBands[i - 1]);
    1189          22 :             CPLAssert(poSrcMEMBand);
    1190             :             auto poNewBand = std::make_unique<MEMRasterBand>(
    1191           0 :                 poNewDS.get(), i, poSrcMEMBand->pabyData,
    1192          22 :                 poSrcMEMBand->GetRasterDataType(), poSrcMEMBand->nPixelOffset,
    1193          22 :                 poSrcMEMBand->nLineOffset,
    1194          44 :                 /* bAssumeOwnership = */ false);
    1195             : 
    1196          22 :             poNewBand->SetDescription(poSrcMEMBand->GetDescription());
    1197          22 :             poNewBand->oMDMD = poSrcMEMBand->oMDMD;
    1198             : 
    1199          22 :             if (poSrcMEMBand->psPam)
    1200             :             {
    1201          22 :                 poNewBand->PamInitialize();
    1202          22 :                 CPLAssert(poNewBand->psPam);
    1203          22 :                 poNewBand->psPam->CopyFrom(*(poSrcMEMBand->psPam));
    1204             :             }
    1205             : 
    1206             :             // Instantiates a mask band when needed.
    1207          22 :             if ((poSrcMEMBand->nMaskFlags &
    1208             :                  (GMF_ALL_VALID | GMF_ALPHA | GMF_NODATA)) == 0)
    1209             :             {
    1210           0 :                 auto poSrcMaskBand = dynamic_cast<const MEMRasterBand *>(
    1211           2 :                     poSrcMEMBand->poMask.get());
    1212           2 :                 if (poSrcMaskBand)
    1213             :                 {
    1214             :                     auto poMaskBand =
    1215             :                         std::unique_ptr<MEMRasterBand>(new MEMRasterBand(
    1216           2 :                             poSrcMaskBand->pabyData, GDT_UInt8, nRasterXSize,
    1217           2 :                             nRasterYSize, /* bOwnData = */ false));
    1218           2 :                     poMaskBand->m_bIsMask = true;
    1219           2 :                     poNewBand->poMask.reset(std::move(poMaskBand));
    1220           2 :                     poNewBand->nMaskFlags = poSrcMaskBand->nMaskFlags;
    1221             :                 }
    1222             :             }
    1223             : 
    1224          22 :             poNewDS->SetBand(i, std::move(poNewBand));
    1225             :         }
    1226             : 
    1227          16 :         return poNewDS;
    1228             :     }
    1229           0 :     return GDALDataset::Clone(nScopeFlags, bCanShareState);
    1230             : }
    1231             : 
    1232             : /************************************************************************/
    1233             : /*                                Open()                                */
    1234             : /************************************************************************/
    1235             : 
    1236          13 : GDALDataset *MEMDataset::Open(GDALOpenInfo *poOpenInfo)
    1237             : 
    1238             : {
    1239             :     /* -------------------------------------------------------------------- */
    1240             :     /*      Do we have the special filename signature for MEM format        */
    1241             :     /*      description strings?                                            */
    1242             :     /* -------------------------------------------------------------------- */
    1243          13 :     if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "MEM:::") ||
    1244          13 :         poOpenInfo->fpL != nullptr)
    1245           0 :         return nullptr;
    1246             : 
    1247             : #ifndef GDAL_MEM_ENABLE_OPEN
    1248          13 :     if (!CPLTestBool(CPLGetConfigOption("GDAL_MEM_ENABLE_OPEN", "NO")))
    1249             :     {
    1250           6 :         CPLError(CE_Failure, CPLE_AppDefined,
    1251             :                  "Opening a MEM dataset with the MEM:::DATAPOINTER= syntax "
    1252             :                  "is no longer supported by default for security reasons. "
    1253             :                  "If you want to allow it, define the "
    1254             :                  "GDAL_MEM_ENABLE_OPEN "
    1255             :                  "configuration option to YES, or build GDAL with the "
    1256             :                  "GDAL_MEM_ENABLE_OPEN compilation definition");
    1257           6 :         return nullptr;
    1258             :     }
    1259             : #endif
    1260             : 
    1261             :     const CPLStringList aosOptions(CSLTokenizeStringComplex(
    1262          14 :         poOpenInfo->pszFilename + 6, ",", TRUE, FALSE));
    1263             : 
    1264             :     /* -------------------------------------------------------------------- */
    1265             :     /*      Verify we have all required fields                              */
    1266             :     /* -------------------------------------------------------------------- */
    1267           7 :     if (aosOptions.FetchNameValue("PIXELS") == nullptr ||
    1268          14 :         aosOptions.FetchNameValue("LINES") == nullptr ||
    1269           7 :         aosOptions.FetchNameValue("DATAPOINTER") == nullptr)
    1270             :     {
    1271           0 :         CPLError(
    1272             :             CE_Failure, CPLE_AppDefined,
    1273             :             "Missing required field (one of PIXELS, LINES or DATAPOINTER).  "
    1274             :             "Unable to access in-memory array.");
    1275             : 
    1276           0 :         return nullptr;
    1277             :     }
    1278             : 
    1279             :     /* -------------------------------------------------------------------- */
    1280             :     /*      Create the new MEMDataset object.                               */
    1281             :     /* -------------------------------------------------------------------- */
    1282          14 :     auto poDS = std::make_unique<MEMDataset>();
    1283             : 
    1284           7 :     poDS->nRasterXSize = atoi(aosOptions.FetchNameValue("PIXELS"));
    1285           7 :     poDS->nRasterYSize = atoi(aosOptions.FetchNameValue("LINES"));
    1286           7 :     poDS->eAccess = poOpenInfo->eAccess;
    1287             : 
    1288             :     /* -------------------------------------------------------------------- */
    1289             :     /*      Extract other information.                                      */
    1290             :     /* -------------------------------------------------------------------- */
    1291           7 :     const char *pszOption = aosOptions.FetchNameValue("BANDS");
    1292           7 :     int nBands = 1;
    1293           7 :     if (pszOption != nullptr)
    1294             :     {
    1295           2 :         nBands = atoi(pszOption);
    1296             :     }
    1297             : 
    1298          14 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
    1299           7 :         !GDALCheckBandCount(nBands, TRUE))
    1300             :     {
    1301           0 :         return nullptr;
    1302             :     }
    1303             : 
    1304           7 :     pszOption = aosOptions.FetchNameValue("DATATYPE");
    1305           7 :     GDALDataType eType = GDT_UInt8;
    1306           7 :     if (pszOption != nullptr)
    1307             :     {
    1308           7 :         if (atoi(pszOption) > 0 && atoi(pszOption) < GDT_TypeCount)
    1309           0 :             eType = static_cast<GDALDataType>(atoi(pszOption));
    1310             :         else
    1311             :         {
    1312           7 :             eType = GDALGetDataTypeByName(pszOption);
    1313           7 :             if (eType == GDT_Unknown)
    1314             :             {
    1315           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1316             :                          "DATATYPE=%s not recognised.", pszOption);
    1317           0 :                 return nullptr;
    1318             :             }
    1319             :         }
    1320             :     }
    1321             : 
    1322           7 :     pszOption = aosOptions.FetchNameValue("PIXELOFFSET");
    1323             :     GSpacing nPixelOffset;
    1324           7 :     if (pszOption == nullptr)
    1325           5 :         nPixelOffset = GDALGetDataTypeSizeBytes(eType);
    1326             :     else
    1327           2 :         nPixelOffset =
    1328           2 :             CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption)));
    1329             : 
    1330           7 :     pszOption = aosOptions.FetchNameValue("LINEOFFSET");
    1331           7 :     GSpacing nLineOffset = 0;
    1332           7 :     if (pszOption == nullptr)
    1333           5 :         nLineOffset = poDS->nRasterXSize * static_cast<size_t>(nPixelOffset);
    1334             :     else
    1335           2 :         nLineOffset =
    1336           2 :             CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption)));
    1337             : 
    1338           7 :     pszOption = aosOptions.FetchNameValue("BANDOFFSET");
    1339           7 :     GSpacing nBandOffset = 0;
    1340           7 :     if (pszOption == nullptr)
    1341           5 :         nBandOffset = nLineOffset * static_cast<size_t>(poDS->nRasterYSize);
    1342             :     else
    1343           2 :         nBandOffset =
    1344           2 :             CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption)));
    1345             : 
    1346           7 :     const char *pszDataPointer = aosOptions.FetchNameValue("DATAPOINTER");
    1347          14 :     GByte *pabyData = static_cast<GByte *>(CPLScanPointer(
    1348           7 :         pszDataPointer, static_cast<int>(strlen(pszDataPointer))));
    1349             : 
    1350             :     /* -------------------------------------------------------------------- */
    1351             :     /*      Create band information objects.                                */
    1352             :     /* -------------------------------------------------------------------- */
    1353          14 :     for (int iBand = 0; iBand < nBands; iBand++)
    1354             :     {
    1355          14 :         poDS->SetBand(iBand + 1,
    1356           7 :                       std::make_unique<MEMRasterBand>(
    1357           7 :                           poDS.get(), iBand + 1, pabyData + iBand * nBandOffset,
    1358          14 :                           eType, nPixelOffset, nLineOffset, FALSE));
    1359             :     }
    1360             : 
    1361             :     /* -------------------------------------------------------------------- */
    1362             :     /*      Set GeoTransform information.                                   */
    1363             :     /* -------------------------------------------------------------------- */
    1364             : 
    1365           7 :     pszOption = aosOptions.FetchNameValue("GEOTRANSFORM");
    1366           7 :     if (pszOption != nullptr)
    1367             :     {
    1368             :         const CPLStringList values(
    1369           6 :             CSLTokenizeStringComplex(pszOption, "/", TRUE, FALSE));
    1370           3 :         if (values.size() == 6)
    1371             :         {
    1372           3 :             GDALGeoTransform gt;
    1373          21 :             for (size_t i = 0; i < 6; ++i)
    1374             :             {
    1375          18 :                 gt[i] = CPLScanDouble(values[i],
    1376          18 :                                       static_cast<int>(strlen(values[i])));
    1377             :             }
    1378           3 :             poDS->SetGeoTransform(gt);
    1379             :         }
    1380             :     }
    1381             : 
    1382             :     /* -------------------------------------------------------------------- */
    1383             :     /*      Set Projection Information                                      */
    1384             :     /* -------------------------------------------------------------------- */
    1385             : 
    1386           7 :     pszOption = aosOptions.FetchNameValue("SPATIALREFERENCE");
    1387           7 :     if (pszOption != nullptr)
    1388             :     {
    1389           3 :         poDS->m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1390           3 :         if (poDS->m_oSRS.SetFromUserInput(pszOption) != OGRERR_NONE)
    1391             :         {
    1392           1 :             CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized crs: %s",
    1393             :                      pszOption);
    1394             :         }
    1395             :     }
    1396             :     /* -------------------------------------------------------------------- */
    1397             :     /*      Try to return a regular handle on the file.                     */
    1398             :     /* -------------------------------------------------------------------- */
    1399           7 :     return poDS.release();
    1400             : }
    1401             : 
    1402             : /************************************************************************/
    1403             : /*                               Create()                               */
    1404             : /************************************************************************/
    1405             : 
    1406       35532 : MEMDataset *MEMDataset::Create(const char * /* pszFilename */, int nXSize,
    1407             :                                int nYSize, int nBandsIn, GDALDataType eType,
    1408             :                                CSLConstList papszOptions)
    1409             : {
    1410             : 
    1411             :     /* -------------------------------------------------------------------- */
    1412             :     /*      Do we want a pixel interleaved buffer?  I mostly care about     */
    1413             :     /*      this to test pixel interleaved IO in other contexts, but it     */
    1414             :     /*      could be useful to create a directly accessible buffer for      */
    1415             :     /*      some apps.                                                      */
    1416             :     /* -------------------------------------------------------------------- */
    1417       35532 :     bool bPixelInterleaved = false;
    1418       35532 :     const char *pszOption = CSLFetchNameValue(papszOptions, GDALMD_INTERLEAVE);
    1419       35532 :     if (pszOption && EQUAL(pszOption, "PIXEL"))
    1420         169 :         bPixelInterleaved = true;
    1421             : 
    1422             :     /* -------------------------------------------------------------------- */
    1423             :     /*      First allocate band data, verifying that we can get enough      */
    1424             :     /*      memory.                                                         */
    1425             :     /* -------------------------------------------------------------------- */
    1426       35532 :     const int nWordSize = GDALGetDataTypeSizeBytes(eType);
    1427       35532 :     if (nBandsIn > 0 && nWordSize > 0 &&
    1428       10411 :         (nBandsIn > INT_MAX / nWordSize ||
    1429       10410 :          static_cast<GIntBig>(nXSize) * nYSize >
    1430       10410 :              GINTBIG_MAX / (nWordSize * nBandsIn)))
    1431             :     {
    1432           3 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Multiplication overflow");
    1433           3 :         return nullptr;
    1434             :     }
    1435             : 
    1436       35529 :     const GUIntBig nGlobalBigSize =
    1437       35529 :         static_cast<GUIntBig>(nWordSize) * nBandsIn * nXSize * nYSize;
    1438       35529 :     const size_t nGlobalSize = static_cast<size_t>(nGlobalBigSize);
    1439             : #if SIZEOF_VOIDP == 4
    1440             :     if (static_cast<GUIntBig>(nGlobalSize) != nGlobalBigSize)
    1441             :     {
    1442             :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1443             :                  "Cannot allocate " CPL_FRMT_GUIB " bytes on this platform.",
    1444             :                  nGlobalBigSize);
    1445             :         return nullptr;
    1446             :     }
    1447             : #endif
    1448             : 
    1449       71058 :     std::vector<GByte *> apbyBandData;
    1450       35529 :     if (nBandsIn > 0)
    1451             :     {
    1452             :         GByte *pabyData =
    1453       10408 :             static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nGlobalSize));
    1454       10408 :         if (!pabyData)
    1455             :         {
    1456           2 :             return nullptr;
    1457             :         }
    1458             : 
    1459       10406 :         if (bPixelInterleaved)
    1460             :         {
    1461        2276 :             for (int iBand = 0; iBand < nBandsIn; iBand++)
    1462             :             {
    1463        2108 :                 apbyBandData.push_back(pabyData + iBand * nWordSize);
    1464             :             }
    1465             :         }
    1466             :         else
    1467             :         {
    1468      106446 :             for (int iBand = 0; iBand < nBandsIn; iBand++)
    1469             :             {
    1470       96208 :                 apbyBandData.push_back(
    1471       96208 :                     pabyData +
    1472       96208 :                     (static_cast<size_t>(nWordSize) * nXSize * nYSize) * iBand);
    1473             :             }
    1474             :         }
    1475             :     }
    1476             : 
    1477             :     /* -------------------------------------------------------------------- */
    1478             :     /*      Create the new GTiffDataset object.                             */
    1479             :     /* -------------------------------------------------------------------- */
    1480       35527 :     MEMDataset *poDS = new MEMDataset();
    1481             : 
    1482       35527 :     poDS->nRasterXSize = nXSize;
    1483       35527 :     poDS->nRasterYSize = nYSize;
    1484       35527 :     poDS->eAccess = GA_Update;
    1485             : 
    1486       35527 :     const char *pszPixelType = CSLFetchNameValue(papszOptions, "PIXELTYPE");
    1487       35527 :     if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
    1488           0 :         poDS->SetMetadataItem("PIXELTYPE", "SIGNEDBYTE",
    1489           0 :                               GDAL_MDD_IMAGE_STRUCTURE);
    1490             : 
    1491       35527 :     if (nXSize != 0 && nYSize != 0)
    1492             :     {
    1493       33608 :         if (bPixelInterleaved)
    1494         168 :             poDS->SetMetadataItem(GDALMD_INTERLEAVE, "PIXEL",
    1495         168 :                                   GDAL_MDD_IMAGE_STRUCTURE);
    1496             :         else
    1497       33440 :             poDS->SetMetadataItem(GDALMD_INTERLEAVE, "BAND",
    1498       33440 :                                   GDAL_MDD_IMAGE_STRUCTURE);
    1499             :     }
    1500             : 
    1501             :     /* -------------------------------------------------------------------- */
    1502             :     /*      Create band information objects.                                */
    1503             :     /* -------------------------------------------------------------------- */
    1504      133843 :     for (int iBand = 0; iBand < nBandsIn; iBand++)
    1505             :     {
    1506       98316 :         MEMRasterBand *poNewBand = nullptr;
    1507             : 
    1508       98316 :         if (bPixelInterleaved)
    1509        2108 :             poNewBand = new MEMRasterBand(
    1510        2108 :                 poDS, iBand + 1, apbyBandData[iBand], eType,
    1511        2108 :                 cpl::fits_on<int>(nWordSize * nBandsIn), 0, iBand == 0);
    1512             :         else
    1513      192416 :             poNewBand = new MEMRasterBand(poDS, iBand + 1, apbyBandData[iBand],
    1514       96208 :                                           eType, 0, 0, iBand == 0);
    1515             : 
    1516       98316 :         if (const char *pszNBITS =
    1517       98316 :                 CSLFetchNameValue(papszOptions, GDALMD_NBITS))
    1518             :         {
    1519           0 :             poNewBand->SetMetadataItem(GDALMD_NBITS, pszNBITS,
    1520           0 :                                        GDAL_MDD_IMAGE_STRUCTURE);
    1521             :         }
    1522             : 
    1523       98316 :         poDS->SetBand(iBand + 1, poNewBand);
    1524             :     }
    1525             : 
    1526             :     /* -------------------------------------------------------------------- */
    1527             :     /*      Try to return a regular handle on the file.                     */
    1528             :     /* -------------------------------------------------------------------- */
    1529       35527 :     return poDS;
    1530             : }
    1531             : 
    1532       11884 : GDALDataset *MEMDataset::CreateBase(const char *pszFilename, int nXSize,
    1533             :                                     int nYSize, int nBandsIn,
    1534             :                                     GDALDataType eType,
    1535             :                                     CSLConstList papszOptions)
    1536             : {
    1537       11884 :     return Create(pszFilename, nXSize, nYSize, nBandsIn, eType, papszOptions);
    1538             : }
    1539             : 
    1540             : /************************************************************************/
    1541             : /*                        ~MEMAttributeHolder()                         */
    1542             : /************************************************************************/
    1543             : 
    1544             : MEMAttributeHolder::~MEMAttributeHolder() = default;
    1545             : 
    1546             : /************************************************************************/
    1547             : /*                          RenameAttribute()                           */
    1548             : /************************************************************************/
    1549             : 
    1550          10 : bool MEMAttributeHolder::RenameAttribute(const std::string &osOldName,
    1551             :                                          const std::string &osNewName)
    1552             : {
    1553          10 :     if (m_oMapAttributes.find(osNewName) != m_oMapAttributes.end())
    1554             :     {
    1555           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    1556             :                  "An attribute with same name already exists");
    1557           2 :         return false;
    1558             :     }
    1559           8 :     auto oIter = m_oMapAttributes.find(osOldName);
    1560           8 :     if (oIter == m_oMapAttributes.end())
    1561             :     {
    1562           0 :         CPLAssert(false);
    1563             :         return false;
    1564             :     }
    1565           8 :     auto poAttr = std::move(oIter->second);
    1566           8 :     m_oMapAttributes.erase(oIter);
    1567           8 :     m_oMapAttributes[osNewName] = std::move(poAttr);
    1568           8 :     return true;
    1569             : }
    1570             : 
    1571             : /************************************************************************/
    1572             : /*                          GetMDArrayNames()                           */
    1573             : /************************************************************************/
    1574             : 
    1575          52 : std::vector<std::string> MEMGroup::GetMDArrayNames(CSLConstList) const
    1576             : {
    1577          52 :     if (!CheckValidAndErrorOutIfNot())
    1578           2 :         return {};
    1579         100 :     std::vector<std::string> names;
    1580         103 :     for (const auto &iter : m_oMapMDArrays)
    1581          53 :         names.push_back(iter.first);
    1582          50 :     return names;
    1583             : }
    1584             : 
    1585             : /************************************************************************/
    1586             : /*                            OpenMDArray()                             */
    1587             : /************************************************************************/
    1588             : 
    1589         229 : std::shared_ptr<GDALMDArray> MEMGroup::OpenMDArray(const std::string &osName,
    1590             :                                                    CSLConstList) const
    1591             : {
    1592         229 :     if (!CheckValidAndErrorOutIfNot())
    1593           0 :         return nullptr;
    1594         229 :     auto oIter = m_oMapMDArrays.find(osName);
    1595         229 :     if (oIter != m_oMapMDArrays.end())
    1596         169 :         return oIter->second;
    1597          60 :     return nullptr;
    1598             : }
    1599             : 
    1600             : /************************************************************************/
    1601             : /*                           GetGroupNames()                            */
    1602             : /************************************************************************/
    1603             : 
    1604          69 : std::vector<std::string> MEMGroup::GetGroupNames(CSLConstList) const
    1605             : {
    1606          69 :     if (!CheckValidAndErrorOutIfNot())
    1607           0 :         return {};
    1608         138 :     std::vector<std::string> names;
    1609         112 :     for (const auto &iter : m_oMapGroups)
    1610          43 :         names.push_back(iter.first);
    1611          69 :     return names;
    1612             : }
    1613             : 
    1614             : /************************************************************************/
    1615             : /*                             OpenGroup()                              */
    1616             : /************************************************************************/
    1617             : 
    1618          69 : std::shared_ptr<GDALGroup> MEMGroup::OpenGroup(const std::string &osName,
    1619             :                                                CSLConstList) const
    1620             : {
    1621          69 :     if (!CheckValidAndErrorOutIfNot())
    1622           0 :         return nullptr;
    1623          69 :     auto oIter = m_oMapGroups.find(osName);
    1624          69 :     if (oIter != m_oMapGroups.end())
    1625          59 :         return oIter->second;
    1626          10 :     return nullptr;
    1627             : }
    1628             : 
    1629             : /************************************************************************/
    1630             : /*                               Create()                               */
    1631             : /************************************************************************/
    1632             : 
    1633             : /*static*/
    1634        7187 : std::shared_ptr<MEMGroup> MEMGroup::Create(const std::string &osParentName,
    1635             :                                            const char *pszName)
    1636             : {
    1637             :     auto newGroup(
    1638        7187 :         std::shared_ptr<MEMGroup>(new MEMGroup(osParentName, pszName)));
    1639        7187 :     newGroup->SetSelf(newGroup);
    1640        7187 :     if (osParentName.empty())
    1641        2193 :         newGroup->m_poRootGroupWeak = newGroup;
    1642        7187 :     return newGroup;
    1643             : }
    1644             : 
    1645             : /************************************************************************/
    1646             : /*                            CreateGroup()                             */
    1647             : /************************************************************************/
    1648             : 
    1649          35 : std::shared_ptr<GDALGroup> MEMGroup::CreateGroup(const std::string &osName,
    1650             :                                                  CSLConstList /*papszOptions*/)
    1651             : {
    1652          35 :     if (!CheckValidAndErrorOutIfNot())
    1653           0 :         return nullptr;
    1654          35 :     if (osName.empty())
    1655             :     {
    1656           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1657             :                  "Empty group name not supported");
    1658           1 :         return nullptr;
    1659             :     }
    1660          34 :     if (m_oMapGroups.find(osName) != m_oMapGroups.end())
    1661             :     {
    1662           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1663             :                  "A group with same name already exists");
    1664           0 :         return nullptr;
    1665             :     }
    1666          68 :     auto newGroup = MEMGroup::Create(GetFullName(), osName.c_str());
    1667          34 :     newGroup->m_pParent = std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock());
    1668          34 :     newGroup->m_poRootGroupWeak = m_poRootGroupWeak;
    1669          34 :     m_oMapGroups[osName] = newGroup;
    1670          34 :     return newGroup;
    1671             : }
    1672             : 
    1673             : /************************************************************************/
    1674             : /*                            DeleteGroup()                             */
    1675             : /************************************************************************/
    1676             : 
    1677           2 : bool MEMGroup::DeleteGroup(const std::string &osName,
    1678             :                            CSLConstList /*papszOptions*/)
    1679             : {
    1680           2 :     if (!CheckValidAndErrorOutIfNot())
    1681           0 :         return false;
    1682           2 :     auto oIter = m_oMapGroups.find(osName);
    1683           2 :     if (oIter == m_oMapGroups.end())
    1684             :     {
    1685           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1686             :                  "Group %s is not a sub-group of this group", osName.c_str());
    1687           1 :         return false;
    1688             :     }
    1689             : 
    1690           1 :     oIter->second->Deleted();
    1691           1 :     m_oMapGroups.erase(oIter);
    1692           1 :     return true;
    1693             : }
    1694             : 
    1695             : /************************************************************************/
    1696             : /*                      NotifyChildrenOfDeletion()                      */
    1697             : /************************************************************************/
    1698             : 
    1699          20 : void MEMGroup::NotifyChildrenOfDeletion()
    1700             : {
    1701          21 :     for (const auto &oIter : m_oMapGroups)
    1702           1 :         oIter.second->ParentDeleted();
    1703          21 :     for (const auto &oIter : m_oMapMDArrays)
    1704           1 :         oIter.second->ParentDeleted();
    1705          41 :     for (const auto &oIter : m_oMapAttributes)
    1706          21 :         oIter.second->ParentDeleted();
    1707          20 :     for (const auto &oIter : m_oMapDimensions)
    1708           0 :         oIter.second->ParentDeleted();
    1709          20 : }
    1710             : 
    1711             : /************************************************************************/
    1712             : /*                           CreateMDArray()                            */
    1713             : /************************************************************************/
    1714             : 
    1715         332 : std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray(
    1716             :     const std::string &osName,
    1717             :     const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
    1718             :     const GDALExtendedDataType &oType, void *pData, CSLConstList papszOptions)
    1719             : {
    1720         332 :     if (!CheckValidAndErrorOutIfNot())
    1721           0 :         return nullptr;
    1722         332 :     if (osName.empty())
    1723             :     {
    1724           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1725             :                  "Empty array name not supported");
    1726           1 :         return nullptr;
    1727             :     }
    1728         331 :     if (m_oMapMDArrays.find(osName) != m_oMapMDArrays.end())
    1729             :     {
    1730           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1731             :                  "An array with same name already exists");
    1732           1 :         return nullptr;
    1733             :     }
    1734             :     auto newArray(
    1735         660 :         MEMMDArray::Create(GetFullName(), osName, aoDimensions, oType));
    1736             : 
    1737         330 :     GByte *pabyData = nullptr;
    1738         660 :     std::vector<GPtrDiff_t> anStrides;
    1739         330 :     if (pData)
    1740             :     {
    1741          28 :         pabyData = static_cast<GByte *>(pData);
    1742          28 :         const char *pszStrides = CSLFetchNameValue(papszOptions, "STRIDES");
    1743          28 :         if (pszStrides)
    1744             :         {
    1745          28 :             CPLStringList aosStrides(CSLTokenizeString2(pszStrides, ",", 0));
    1746          28 :             if (static_cast<size_t>(aosStrides.size()) != aoDimensions.size())
    1747             :             {
    1748           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1749             :                          "Invalid number of strides");
    1750           0 :                 return nullptr;
    1751             :             }
    1752          76 :             for (int i = 0; i < aosStrides.size(); i++)
    1753             :             {
    1754          48 :                 const auto nStride = CPLAtoGIntBig(aosStrides[i]);
    1755          48 :                 anStrides.push_back(static_cast<GPtrDiff_t>(nStride));
    1756             :             }
    1757             :         }
    1758             :     }
    1759         330 :     if (!newArray->Init(pabyData, anStrides))
    1760           2 :         return nullptr;
    1761             : 
    1762         855 :     for (auto &poDim : newArray->GetDimensions())
    1763             :     {
    1764        1054 :         const auto dim = std::dynamic_pointer_cast<MEMDimension>(poDim);
    1765         527 :         if (dim)
    1766         520 :             dim->RegisterUsingArray(newArray.get());
    1767             :     }
    1768             : 
    1769         328 :     newArray->RegisterGroup(m_pSelf);
    1770         328 :     m_oMapMDArrays[osName] = newArray;
    1771         328 :     return newArray;
    1772             : }
    1773             : 
    1774         304 : std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray(
    1775             :     const std::string &osName,
    1776             :     const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
    1777             :     const GDALExtendedDataType &oType, CSLConstList papszOptions)
    1778             : {
    1779         304 :     void *pData = nullptr;
    1780         304 :     const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER");
    1781         304 :     if (pszDataPointer)
    1782             :     {
    1783             :         // Will not work on architectures with "capability pointers"
    1784           0 :         pData = CPLScanPointer(pszDataPointer,
    1785           0 :                                static_cast<int>(strlen(pszDataPointer)));
    1786             :     }
    1787         304 :     return CreateMDArray(osName, aoDimensions, oType, pData, papszOptions);
    1788             : }
    1789             : 
    1790             : /************************************************************************/
    1791             : /*                           DeleteMDArray()                            */
    1792             : /************************************************************************/
    1793             : 
    1794           2 : bool MEMGroup::DeleteMDArray(const std::string &osName,
    1795             :                              CSLConstList /*papszOptions*/)
    1796             : {
    1797           2 :     if (!CheckValidAndErrorOutIfNot())
    1798           0 :         return false;
    1799           2 :     auto oIter = m_oMapMDArrays.find(osName);
    1800           2 :     if (oIter == m_oMapMDArrays.end())
    1801             :     {
    1802           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1803             :                  "Array %s is not an array of this group", osName.c_str());
    1804           1 :         return false;
    1805             :     }
    1806             : 
    1807           1 :     oIter->second->Deleted();
    1808           1 :     m_oMapMDArrays.erase(oIter);
    1809           1 :     return true;
    1810             : }
    1811             : 
    1812             : /************************************************************************/
    1813             : /*                       MEMGroupCreateMDArray()                        */
    1814             : /************************************************************************/
    1815             : 
    1816             : // Used by NUMPYMultiDimensionalDataset
    1817          28 : std::shared_ptr<GDALMDArray> MEMGroupCreateMDArray(
    1818             :     GDALGroup *poGroup, const std::string &osName,
    1819             :     const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
    1820             :     const GDALExtendedDataType &oDataType, void *pData,
    1821             :     CSLConstList papszOptions)
    1822             : {
    1823          28 :     auto poMemGroup = dynamic_cast<MEMGroup *>(poGroup);
    1824          28 :     if (!poMemGroup)
    1825             :     {
    1826           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1827             :                  "MEMGroupCreateMDArray(): poGroup not of type MEMGroup");
    1828           0 :         return nullptr;
    1829             :     }
    1830             :     return poMemGroup->CreateMDArray(osName, aoDimensions, oDataType, pData,
    1831          28 :                                      papszOptions);
    1832             : }
    1833             : 
    1834             : /************************************************************************/
    1835             : /*                            GetAttribute()                            */
    1836             : /************************************************************************/
    1837             : 
    1838             : std::shared_ptr<GDALAttribute>
    1839        9415 : MEMGroup::GetAttribute(const std::string &osName) const
    1840             : {
    1841        9415 :     if (!CheckValidAndErrorOutIfNot())
    1842           3 :         return nullptr;
    1843        9412 :     auto oIter = m_oMapAttributes.find(osName);
    1844        9412 :     if (oIter != m_oMapAttributes.end())
    1845         476 :         return oIter->second;
    1846        8936 :     return nullptr;
    1847             : }
    1848             : 
    1849             : /************************************************************************/
    1850             : /*                           GetAttributes()                            */
    1851             : /************************************************************************/
    1852             : 
    1853             : std::vector<std::shared_ptr<GDALAttribute>>
    1854       22109 : MEMGroup::GetAttributes(CSLConstList) const
    1855             : {
    1856       22109 :     if (!CheckValidAndErrorOutIfNot())
    1857           6 :         return {};
    1858       44206 :     std::vector<std::shared_ptr<GDALAttribute>> oRes;
    1859       27525 :     for (const auto &oIter : m_oMapAttributes)
    1860             :     {
    1861        5422 :         oRes.push_back(oIter.second);
    1862             :     }
    1863       22103 :     return oRes;
    1864             : }
    1865             : 
    1866             : /************************************************************************/
    1867             : /*                           GetDimensions()                            */
    1868             : /************************************************************************/
    1869             : 
    1870             : std::vector<std::shared_ptr<GDALDimension>>
    1871          73 : MEMGroup::GetDimensions(CSLConstList) const
    1872             : {
    1873          73 :     if (!CheckValidAndErrorOutIfNot())
    1874           0 :         return {};
    1875         146 :     std::vector<std::shared_ptr<GDALDimension>> oRes;
    1876         266 :     for (const auto &oIter : m_oMapDimensions)
    1877             :     {
    1878         193 :         oRes.push_back(oIter.second);
    1879             :     }
    1880          73 :     return oRes;
    1881             : }
    1882             : 
    1883             : /************************************************************************/
    1884             : /*                          CreateAttribute()                           */
    1885             : /************************************************************************/
    1886             : 
    1887             : std::shared_ptr<GDALAttribute>
    1888        1582 : MEMGroup::CreateAttribute(const std::string &osName,
    1889             :                           const std::vector<GUInt64> &anDimensions,
    1890             :                           const GDALExtendedDataType &oDataType, CSLConstList)
    1891             : {
    1892        1582 :     if (!CheckValidAndErrorOutIfNot())
    1893           0 :         return nullptr;
    1894        1582 :     if (osName.empty())
    1895             :     {
    1896           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1897             :                  "Empty attribute name not supported");
    1898           1 :         return nullptr;
    1899             :     }
    1900        1581 :     if (m_oMapAttributes.find(osName) != m_oMapAttributes.end())
    1901             :     {
    1902           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1903             :                  "An attribute with same name already exists");
    1904           0 :         return nullptr;
    1905             :     }
    1906             :     auto newAttr(MEMAttribute::Create(
    1907        3162 :         std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()), osName,
    1908        3162 :         anDimensions, oDataType));
    1909        1581 :     if (!newAttr)
    1910           0 :         return nullptr;
    1911        1581 :     m_oMapAttributes[osName] = newAttr;
    1912        1581 :     return newAttr;
    1913             : }
    1914             : 
    1915             : /************************************************************************/
    1916             : /*                          DeleteAttribute()                           */
    1917             : /************************************************************************/
    1918             : 
    1919          30 : bool MEMGroup::DeleteAttribute(const std::string &osName,
    1920             :                                CSLConstList /*papszOptions*/)
    1921             : {
    1922          30 :     if (!CheckValidAndErrorOutIfNot())
    1923           0 :         return false;
    1924          30 :     auto oIter = m_oMapAttributes.find(osName);
    1925          30 :     if (oIter == m_oMapAttributes.end())
    1926             :     {
    1927          13 :         CPLError(CE_Failure, CPLE_AppDefined,
    1928             :                  "Attribute %s is not an attribute of this group",
    1929             :                  osName.c_str());
    1930          13 :         return false;
    1931             :     }
    1932             : 
    1933          17 :     oIter->second->Deleted();
    1934          17 :     m_oMapAttributes.erase(oIter);
    1935          17 :     return true;
    1936             : }
    1937             : 
    1938             : /************************************************************************/
    1939             : /*                               Rename()                               */
    1940             : /************************************************************************/
    1941             : 
    1942           4 : bool MEMGroup::Rename(const std::string &osNewName)
    1943             : {
    1944           4 :     if (!CheckValidAndErrorOutIfNot())
    1945           0 :         return false;
    1946           4 :     if (osNewName.empty())
    1947             :     {
    1948           1 :         CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
    1949           1 :         return false;
    1950             :     }
    1951           3 :     if (m_osName == "/")
    1952             :     {
    1953           1 :         CPLError(CE_Failure, CPLE_NotSupported, "Cannot rename root group");
    1954           1 :         return false;
    1955             :     }
    1956           4 :     auto pParent = m_pParent.lock();
    1957           2 :     if (pParent)
    1958             :     {
    1959           2 :         if (pParent->m_oMapGroups.find(osNewName) !=
    1960           4 :             pParent->m_oMapGroups.end())
    1961             :         {
    1962           1 :             CPLError(CE_Failure, CPLE_AppDefined,
    1963             :                      "A group with same name already exists");
    1964           1 :             return false;
    1965             :         }
    1966           1 :         pParent->m_oMapGroups.erase(pParent->m_oMapGroups.find(m_osName));
    1967             :     }
    1968             : 
    1969           1 :     BaseRename(osNewName);
    1970             : 
    1971           1 :     if (pParent)
    1972             :     {
    1973           1 :         CPLAssert(m_pSelf.lock());
    1974           1 :         pParent->m_oMapGroups[m_osName] = m_pSelf.lock();
    1975             :     }
    1976             : 
    1977           1 :     return true;
    1978             : }
    1979             : 
    1980             : /************************************************************************/
    1981             : /*                      NotifyChildrenOfRenaming()                      */
    1982             : /************************************************************************/
    1983             : 
    1984           3 : void MEMGroup::NotifyChildrenOfRenaming()
    1985             : {
    1986           5 :     for (const auto &oIter : m_oMapGroups)
    1987           2 :         oIter.second->ParentRenamed(m_osFullName);
    1988           5 :     for (const auto &oIter : m_oMapMDArrays)
    1989           2 :         oIter.second->ParentRenamed(m_osFullName);
    1990           5 :     for (const auto &oIter : m_oMapAttributes)
    1991           2 :         oIter.second->ParentRenamed(m_osFullName);
    1992           4 :     for (const auto &oIter : m_oMapDimensions)
    1993           1 :         oIter.second->ParentRenamed(m_osFullName);
    1994           3 : }
    1995             : 
    1996             : /************************************************************************/
    1997             : /*                          RenameDimension()                           */
    1998             : /************************************************************************/
    1999             : 
    2000           2 : bool MEMGroup::RenameDimension(const std::string &osOldName,
    2001             :                                const std::string &osNewName)
    2002             : {
    2003           2 :     if (m_oMapDimensions.find(osNewName) != m_oMapDimensions.end())
    2004             :     {
    2005           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    2006             :                  "A dimension with same name already exists");
    2007           1 :         return false;
    2008             :     }
    2009           1 :     auto oIter = m_oMapDimensions.find(osOldName);
    2010           1 :     if (oIter == m_oMapDimensions.end())
    2011             :     {
    2012           0 :         CPLAssert(false);
    2013             :         return false;
    2014             :     }
    2015           1 :     auto poDim = std::move(oIter->second);
    2016           1 :     m_oMapDimensions.erase(oIter);
    2017           1 :     m_oMapDimensions[osNewName] = std::move(poDim);
    2018           1 :     return true;
    2019             : }
    2020             : 
    2021             : /************************************************************************/
    2022             : /*                            RenameArray()                             */
    2023             : /************************************************************************/
    2024             : 
    2025           2 : bool MEMGroup::RenameArray(const std::string &osOldName,
    2026             :                            const std::string &osNewName)
    2027             : {
    2028           2 :     if (m_oMapMDArrays.find(osNewName) != m_oMapMDArrays.end())
    2029             :     {
    2030           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    2031             :                  "An array with same name already exists");
    2032           1 :         return false;
    2033             :     }
    2034           1 :     auto oIter = m_oMapMDArrays.find(osOldName);
    2035           1 :     if (oIter == m_oMapMDArrays.end())
    2036             :     {
    2037           0 :         CPLAssert(false);
    2038             :         return false;
    2039             :     }
    2040           1 :     auto poArray = std::move(oIter->second);
    2041           1 :     m_oMapMDArrays.erase(oIter);
    2042           1 :     m_oMapMDArrays[osNewName] = std::move(poArray);
    2043           1 :     return true;
    2044             : }
    2045             : 
    2046             : /************************************************************************/
    2047             : /*                         MEMAbstractMDArray()                         */
    2048             : /************************************************************************/
    2049             : 
    2050        2083 : MEMAbstractMDArray::MEMAbstractMDArray(
    2051             :     const std::string &osParentName, const std::string &osName,
    2052             :     const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
    2053           0 :     const GDALExtendedDataType &oType)
    2054             :     : GDALAbstractMDArray(osParentName, osName), m_aoDims(aoDimensions),
    2055        2083 :       m_oType(oType)
    2056             : {
    2057        2083 : }
    2058             : 
    2059             : /************************************************************************/
    2060             : /*                        ~MEMAbstractMDArray()                         */
    2061             : /************************************************************************/
    2062             : 
    2063        2079 : MEMAbstractMDArray::~MEMAbstractMDArray()
    2064             : {
    2065        2079 :     FreeArray();
    2066        2079 : }
    2067             : 
    2068             : /************************************************************************/
    2069             : /*                             FreeArray()                              */
    2070             : /************************************************************************/
    2071             : 
    2072        2085 : void MEMAbstractMDArray::FreeArray()
    2073             : {
    2074        2085 :     if (m_bOwnArray)
    2075             :     {
    2076        2037 :         if (m_oType.NeedsFreeDynamicMemory())
    2077             :         {
    2078        1343 :             GByte *pabyPtr = m_pabyArray;
    2079        1343 :             GByte *pabyEnd = m_pabyArray + m_nTotalSize;
    2080        1343 :             const auto nDTSize(m_oType.GetSize());
    2081        2799 :             while (pabyPtr < pabyEnd)
    2082             :             {
    2083        1456 :                 m_oType.FreeDynamicMemory(pabyPtr);
    2084        1456 :                 pabyPtr += nDTSize;
    2085             :             }
    2086             :         }
    2087        2037 :         VSIFree(m_pabyArray);
    2088        2037 :         m_pabyArray = nullptr;
    2089        2037 :         m_nTotalSize = 0;
    2090        2037 :         m_bOwnArray = false;
    2091             :     }
    2092        2085 : }
    2093             : 
    2094             : /************************************************************************/
    2095             : /*                                Init()                                */
    2096             : /************************************************************************/
    2097             : 
    2098        2083 : bool MEMAbstractMDArray::Init(GByte *pData,
    2099             :                               const std::vector<GPtrDiff_t> &anStrides)
    2100             : {
    2101        2083 :     GUInt64 nTotalSize = m_oType.GetSize();
    2102        2083 :     if (!m_aoDims.empty())
    2103             :     {
    2104         573 :         if (anStrides.empty())
    2105             :         {
    2106         545 :             m_anStrides.resize(m_aoDims.size());
    2107             :         }
    2108             :         else
    2109             :         {
    2110          28 :             CPLAssert(anStrides.size() == m_aoDims.size());
    2111          28 :             m_anStrides = anStrides;
    2112             :         }
    2113             : 
    2114             :         // To compute strides we must proceed from the fastest varying dimension
    2115             :         // (the last one), and then reverse the result
    2116        1403 :         for (size_t i = m_aoDims.size(); i != 0;)
    2117             :         {
    2118         833 :             --i;
    2119         833 :             const auto &poDim = m_aoDims[i];
    2120         833 :             auto nDimSize = poDim->GetSize();
    2121         833 :             if (nDimSize == 0)
    2122             :             {
    2123           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    2124             :                          "Illegal dimension size 0");
    2125           0 :                 return false;
    2126             :             }
    2127         833 :             if (nTotalSize > std::numeric_limits<GUInt64>::max() / nDimSize)
    2128             :             {
    2129           3 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
    2130           3 :                 return false;
    2131             :             }
    2132         830 :             auto nNewSize = nTotalSize * nDimSize;
    2133         830 :             if (anStrides.empty())
    2134         782 :                 m_anStrides[i] = static_cast<size_t>(nTotalSize);
    2135         830 :             nTotalSize = nNewSize;
    2136             :         }
    2137             :     }
    2138             : 
    2139             :     // We restrict the size of the allocation so that all elements can be
    2140             :     // indexed by GPtrDiff_t
    2141        2080 :     if (nTotalSize >
    2142        2080 :         static_cast<size_t>(std::numeric_limits<GPtrDiff_t>::max()))
    2143             :     {
    2144           1 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
    2145           1 :         return false;
    2146             :     }
    2147        2079 :     m_nTotalSize = static_cast<size_t>(nTotalSize);
    2148        2079 :     if (pData)
    2149             :     {
    2150          38 :         m_pabyArray = pData;
    2151             :     }
    2152             :     else
    2153             :     {
    2154        2041 :         m_pabyArray = static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, m_nTotalSize));
    2155        2041 :         m_bOwnArray = true;
    2156             :     }
    2157             : 
    2158        2079 :     return m_pabyArray != nullptr;
    2159             : }
    2160             : 
    2161             : /************************************************************************/
    2162             : /*                              FastCopy()                              */
    2163             : /************************************************************************/
    2164             : 
    2165             : template <int N>
    2166         447 : inline static void FastCopy(size_t nIters, GByte *dstPtr, const GByte *srcPtr,
    2167             :                             GPtrDiff_t dst_inc_offset,
    2168             :                             GPtrDiff_t src_inc_offset)
    2169             : {
    2170         447 :     if (nIters >= 8)
    2171             :     {
    2172             : #define COPY_ELT(i)                                                            \
    2173             :     memcpy(dstPtr + (i) * dst_inc_offset, srcPtr + (i) * src_inc_offset, N)
    2174             :         while (true)
    2175             :         {
    2176          43 :             COPY_ELT(0);
    2177          43 :             COPY_ELT(1);
    2178          43 :             COPY_ELT(2);
    2179          43 :             COPY_ELT(3);
    2180          43 :             COPY_ELT(4);
    2181          43 :             COPY_ELT(5);
    2182          43 :             COPY_ELT(6);
    2183          43 :             COPY_ELT(7);
    2184          43 :             nIters -= 8;
    2185          43 :             srcPtr += 8 * src_inc_offset;
    2186          43 :             dstPtr += 8 * dst_inc_offset;
    2187          43 :             if (nIters < 8)
    2188          21 :                 break;
    2189             :         }
    2190          21 :         if (nIters == 0)
    2191           0 :             return;
    2192             :     }
    2193             :     while (true)
    2194             :     {
    2195         654 :         memcpy(dstPtr, srcPtr, N);
    2196         654 :         if ((--nIters) == 0)
    2197         447 :             break;
    2198         207 :         srcPtr += src_inc_offset;
    2199         207 :         dstPtr += dst_inc_offset;
    2200             :     }
    2201             : }
    2202             : 
    2203             : /************************************************************************/
    2204             : /*                             ReadWrite()                              */
    2205             : /************************************************************************/
    2206             : 
    2207        1642 : void MEMAbstractMDArray::ReadWrite(bool bIsWrite, const size_t *count,
    2208             :                                    std::vector<StackReadWrite> &stack,
    2209             :                                    const GDALExtendedDataType &srcType,
    2210             :                                    const GDALExtendedDataType &dstType) const
    2211             : {
    2212        1642 :     const auto nDims = m_aoDims.size();
    2213        1642 :     const auto nDimsMinus1 = nDims - 1;
    2214        3041 :     const bool bBothAreNumericDT = srcType.GetClass() == GEDTC_NUMERIC &&
    2215        1399 :                                    dstType.GetClass() == GEDTC_NUMERIC;
    2216             :     const bool bSameNumericDT =
    2217        3017 :         bBothAreNumericDT &&
    2218        1375 :         srcType.GetNumericDataType() == dstType.GetNumericDataType();
    2219        1642 :     const auto nSameDTSize = bSameNumericDT ? srcType.GetSize() : 0;
    2220             :     const bool bCanUseMemcpyLastDim =
    2221        2771 :         bSameNumericDT &&
    2222        1129 :         stack[nDimsMinus1].src_inc_offset ==
    2223        3556 :             static_cast<GPtrDiff_t>(nSameDTSize) &&
    2224         785 :         stack[nDimsMinus1].dst_inc_offset ==
    2225         785 :             static_cast<GPtrDiff_t>(nSameDTSize);
    2226        1642 :     const size_t nCopySizeLastDim =
    2227        1642 :         bCanUseMemcpyLastDim ? nSameDTSize * count[nDimsMinus1] : 0;
    2228             :     const bool bNeedsFreeDynamicMemory =
    2229        1642 :         bIsWrite && dstType.NeedsFreeDynamicMemory();
    2230             : 
    2231       77703 :     auto lambdaLastDim = [&](size_t idxPtr)
    2232             :     {
    2233       77703 :         auto srcPtr = stack[idxPtr].src_ptr;
    2234       77703 :         auto dstPtr = stack[idxPtr].dst_ptr;
    2235       77703 :         if (nCopySizeLastDim)
    2236             :         {
    2237       76702 :             memcpy(dstPtr, srcPtr, nCopySizeLastDim);
    2238             :         }
    2239             :         else
    2240             :         {
    2241        2002 :             size_t nIters = count[nDimsMinus1];
    2242        1001 :             const auto dst_inc_offset = stack[nDimsMinus1].dst_inc_offset;
    2243        1001 :             const auto src_inc_offset = stack[nDimsMinus1].src_inc_offset;
    2244        1001 :             if (bSameNumericDT)
    2245             :             {
    2246         447 :                 if (nSameDTSize == 1)
    2247             :                 {
    2248          73 :                     FastCopy<1>(nIters, dstPtr, srcPtr, dst_inc_offset,
    2249             :                                 src_inc_offset);
    2250          73 :                     return;
    2251             :                 }
    2252         374 :                 if (nSameDTSize == 2)
    2253             :                 {
    2254          46 :                     FastCopy<2>(nIters, dstPtr, srcPtr, dst_inc_offset,
    2255             :                                 src_inc_offset);
    2256          46 :                     return;
    2257             :                 }
    2258         328 :                 if (nSameDTSize == 4)
    2259             :                 {
    2260          70 :                     FastCopy<4>(nIters, dstPtr, srcPtr, dst_inc_offset,
    2261             :                                 src_inc_offset);
    2262          70 :                     return;
    2263             :                 }
    2264         258 :                 if (nSameDTSize == 8)
    2265             :                 {
    2266         256 :                     FastCopy<8>(nIters, dstPtr, srcPtr, dst_inc_offset,
    2267             :                                 src_inc_offset);
    2268         256 :                     return;
    2269             :                 }
    2270           2 :                 if (nSameDTSize == 16)
    2271             :                 {
    2272           2 :                     FastCopy<16>(nIters, dstPtr, srcPtr, dst_inc_offset,
    2273             :                                  src_inc_offset);
    2274           2 :                     return;
    2275             :                 }
    2276           0 :                 CPLAssert(false);
    2277             :             }
    2278        1108 :             else if (bBothAreNumericDT
    2279             : #if SIZEOF_VOIDP >= 8
    2280         836 :                      && src_inc_offset <= std::numeric_limits<int>::max() &&
    2281         282 :                      dst_inc_offset <= std::numeric_limits<int>::max()
    2282             : #endif
    2283             :             )
    2284             :             {
    2285         282 :                 GDALCopyWords64(srcPtr, srcType.GetNumericDataType(),
    2286             :                                 static_cast<int>(src_inc_offset), dstPtr,
    2287         282 :                                 dstType.GetNumericDataType(),
    2288             :                                 static_cast<int>(dst_inc_offset),
    2289             :                                 static_cast<GPtrDiff_t>(nIters));
    2290         282 :                 return;
    2291             :             }
    2292             : 
    2293             :             while (true)
    2294             :             {
    2295         667 :                 if (bNeedsFreeDynamicMemory)
    2296             :                 {
    2297         177 :                     dstType.FreeDynamicMemory(dstPtr);
    2298             :                 }
    2299         667 :                 GDALExtendedDataType::CopyValue(srcPtr, srcType, dstPtr,
    2300             :                                                 dstType);
    2301         667 :                 if ((--nIters) == 0)
    2302         272 :                     break;
    2303         395 :                 srcPtr += src_inc_offset;
    2304         395 :                 dstPtr += dst_inc_offset;
    2305             :             }
    2306             :         }
    2307        1642 :     };
    2308             : 
    2309        1642 :     if (nDims == 1)
    2310             :     {
    2311        1233 :         lambdaLastDim(0);
    2312             :     }
    2313         409 :     else if (nDims == 2)
    2314             :     {
    2315         169 :         auto nIters = count[0];
    2316             :         while (true)
    2317             :         {
    2318         480 :             lambdaLastDim(0);
    2319         480 :             if ((--nIters) == 0)
    2320         169 :                 break;
    2321         311 :             stack[0].src_ptr += stack[0].src_inc_offset;
    2322         311 :             stack[0].dst_ptr += stack[0].dst_inc_offset;
    2323             :         }
    2324             :     }
    2325         240 :     else if (nDims == 3)
    2326             :     {
    2327         165 :         stack[0].nIters = count[0];
    2328             :         while (true)
    2329             :         {
    2330         266 :             stack[1].src_ptr = stack[0].src_ptr;
    2331         266 :             stack[1].dst_ptr = stack[0].dst_ptr;
    2332         266 :             auto nIters = count[1];
    2333             :             while (true)
    2334             :             {
    2335        2506 :                 lambdaLastDim(1);
    2336        2506 :                 if ((--nIters) == 0)
    2337         266 :                     break;
    2338        2240 :                 stack[1].src_ptr += stack[1].src_inc_offset;
    2339        2240 :                 stack[1].dst_ptr += stack[1].dst_inc_offset;
    2340             :             }
    2341         266 :             if ((--stack[0].nIters) == 0)
    2342         165 :                 break;
    2343         101 :             stack[0].src_ptr += stack[0].src_inc_offset;
    2344         101 :             stack[0].dst_ptr += stack[0].dst_inc_offset;
    2345         101 :         }
    2346             :     }
    2347             :     else
    2348             :     {
    2349             :         // Implementation valid for nDims >= 3
    2350             : 
    2351          75 :         size_t dimIdx = 0;
    2352             :         // Non-recursive implementation. Hence the gotos
    2353             :         // It might be possible to rewrite this without gotos, but I find they
    2354             :         // make it clearer to understand the recursive nature of the code
    2355      150080 :     lbl_next_depth:
    2356      150080 :         if (dimIdx == nDimsMinus1 - 1)
    2357             :         {
    2358       51594 :             auto nIters = count[dimIdx];
    2359             :             while (true)
    2360             :             {
    2361       73484 :                 lambdaLastDim(dimIdx);
    2362       73484 :                 if ((--nIters) == 0)
    2363       51594 :                     break;
    2364       21890 :                 stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
    2365       21890 :                 stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
    2366             :             }
    2367             :             // If there was a test if( dimIdx > 0 ), that would be valid for
    2368             :             // nDims == 2
    2369       51594 :             goto lbl_return_to_caller;
    2370             :         }
    2371             :         else
    2372             :         {
    2373       98486 :             stack[dimIdx].nIters = count[dimIdx];
    2374             :             while (true)
    2375             :             {
    2376      150005 :                 dimIdx++;
    2377      150005 :                 stack[dimIdx].src_ptr = stack[dimIdx - 1].src_ptr;
    2378      150005 :                 stack[dimIdx].dst_ptr = stack[dimIdx - 1].dst_ptr;
    2379      150005 :                 goto lbl_next_depth;
    2380      150005 :             lbl_return_to_caller:
    2381      150005 :                 dimIdx--;
    2382      150005 :                 if ((--stack[dimIdx].nIters) == 0)
    2383       98486 :                     break;
    2384       51519 :                 stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
    2385       51519 :                 stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
    2386             :             }
    2387       98486 :             if (dimIdx > 0)
    2388       98411 :                 goto lbl_return_to_caller;
    2389             :         }
    2390             :     }
    2391        1642 : }
    2392             : 
    2393             : /************************************************************************/
    2394             : /*                               IRead()                                */
    2395             : /************************************************************************/
    2396             : 
    2397        1926 : bool MEMAbstractMDArray::IRead(const GUInt64 *arrayStartIdx,
    2398             :                                const size_t *count, const GInt64 *arrayStep,
    2399             :                                const GPtrDiff_t *bufferStride,
    2400             :                                const GDALExtendedDataType &bufferDataType,
    2401             :                                void *pDstBuffer) const
    2402             : {
    2403        1926 :     if (!CheckValidAndErrorOutIfNot())
    2404           0 :         return false;
    2405             : 
    2406        1926 :     const auto nDims = m_aoDims.size();
    2407        1926 :     if (nDims == 0)
    2408             :     {
    2409        1071 :         GDALExtendedDataType::CopyValue(m_pabyArray, m_oType, pDstBuffer,
    2410             :                                         bufferDataType);
    2411        1071 :         return true;
    2412             :     }
    2413         855 :     std::vector<StackReadWrite> stack(nDims);
    2414         855 :     const auto nBufferDTSize = bufferDataType.GetSize();
    2415         855 :     GPtrDiff_t startSrcOffset = 0;
    2416        2221 :     for (size_t i = 0; i < nDims; i++)
    2417             :     {
    2418        1366 :         startSrcOffset +=
    2419        1366 :             static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]);
    2420        2732 :         stack[i].src_inc_offset =
    2421        1366 :             static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]);
    2422        1366 :         stack[i].dst_inc_offset =
    2423        1366 :             static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize);
    2424             :     }
    2425         855 :     stack[0].src_ptr = m_pabyArray + startSrcOffset;
    2426         855 :     stack[0].dst_ptr = static_cast<GByte *>(pDstBuffer);
    2427             : 
    2428         855 :     ReadWrite(false, count, stack, m_oType, bufferDataType);
    2429         855 :     return true;
    2430             : }
    2431             : 
    2432             : /************************************************************************/
    2433             : /*                               IWrite()                               */
    2434             : /************************************************************************/
    2435             : 
    2436        2270 : bool MEMAbstractMDArray::IWrite(const GUInt64 *arrayStartIdx,
    2437             :                                 const size_t *count, const GInt64 *arrayStep,
    2438             :                                 const GPtrDiff_t *bufferStride,
    2439             :                                 const GDALExtendedDataType &bufferDataType,
    2440             :                                 const void *pSrcBuffer)
    2441             : {
    2442        2270 :     if (!CheckValidAndErrorOutIfNot())
    2443          12 :         return false;
    2444        2258 :     if (!m_bWritable)
    2445             :     {
    2446           2 :         CPLError(CE_Failure, CPLE_AppDefined, "Non updatable object");
    2447           2 :         return false;
    2448             :     }
    2449             : 
    2450        2256 :     m_bModified = true;
    2451             : 
    2452        2256 :     const auto nDims = m_aoDims.size();
    2453        2256 :     if (nDims == 0)
    2454             :     {
    2455        1469 :         m_oType.FreeDynamicMemory(m_pabyArray);
    2456        1469 :         GDALExtendedDataType::CopyValue(pSrcBuffer, bufferDataType, m_pabyArray,
    2457        1469 :                                         m_oType);
    2458        1469 :         return true;
    2459             :     }
    2460         787 :     std::vector<StackReadWrite> stack(nDims);
    2461         787 :     const auto nBufferDTSize = bufferDataType.GetSize();
    2462         787 :     GPtrDiff_t startDstOffset = 0;
    2463        1841 :     for (size_t i = 0; i < nDims; i++)
    2464             :     {
    2465        1054 :         startDstOffset +=
    2466        1054 :             static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]);
    2467        2108 :         stack[i].dst_inc_offset =
    2468        1054 :             static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]);
    2469        1054 :         stack[i].src_inc_offset =
    2470        1054 :             static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize);
    2471             :     }
    2472             : 
    2473         787 :     stack[0].dst_ptr = m_pabyArray + startDstOffset;
    2474         787 :     stack[0].src_ptr = static_cast<const GByte *>(pSrcBuffer);
    2475             : 
    2476         787 :     ReadWrite(true, count, stack, bufferDataType, m_oType);
    2477         787 :     return true;
    2478             : }
    2479             : 
    2480             : /************************************************************************/
    2481             : /*                             MEMMDArray()                             */
    2482             : /************************************************************************/
    2483             : 
    2484         368 : MEMMDArray::MEMMDArray(
    2485             :     const std::string &osParentName, const std::string &osName,
    2486             :     const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
    2487         368 :     const GDALExtendedDataType &oType)
    2488             :     : GDALAbstractMDArray(osParentName, osName),
    2489             :       MEMAbstractMDArray(osParentName, osName, aoDimensions, oType),
    2490         368 :       GDALMDArray(osParentName, osName)
    2491             : {
    2492         368 : }
    2493             : 
    2494             : /************************************************************************/
    2495             : /*                            ~MEMMDArray()                             */
    2496             : /************************************************************************/
    2497             : 
    2498         728 : MEMMDArray::~MEMMDArray()
    2499             : {
    2500         364 :     if (m_pabyNoData)
    2501             :     {
    2502          43 :         m_oType.FreeDynamicMemory(&m_pabyNoData[0]);
    2503          43 :         CPLFree(m_pabyNoData);
    2504             :     }
    2505             : 
    2506         941 :     for (auto &poDim : GetDimensions())
    2507             :     {
    2508        1154 :         const auto dim = std::dynamic_pointer_cast<MEMDimension>(poDim);
    2509         577 :         if (dim)
    2510         536 :             dim->UnRegisterUsingArray(this);
    2511             :     }
    2512         728 : }
    2513             : 
    2514             : /************************************************************************/
    2515             : /*                         GetRawNoDataValue()                          */
    2516             : /************************************************************************/
    2517             : 
    2518         362 : const void *MEMMDArray::GetRawNoDataValue() const
    2519             : {
    2520         362 :     return m_pabyNoData;
    2521             : }
    2522             : 
    2523             : /************************************************************************/
    2524             : /*                         SetRawNoDataValue()                          */
    2525             : /************************************************************************/
    2526             : 
    2527          48 : bool MEMMDArray::SetRawNoDataValue(const void *pNoData)
    2528             : {
    2529          48 :     if (!CheckValidAndErrorOutIfNot())
    2530           0 :         return false;
    2531          48 :     if (m_pabyNoData)
    2532             :     {
    2533           4 :         m_oType.FreeDynamicMemory(&m_pabyNoData[0]);
    2534             :     }
    2535             : 
    2536          48 :     if (pNoData == nullptr)
    2537             :     {
    2538           1 :         CPLFree(m_pabyNoData);
    2539           1 :         m_pabyNoData = nullptr;
    2540             :     }
    2541             :     else
    2542             :     {
    2543          47 :         const auto nSize = m_oType.GetSize();
    2544          47 :         if (m_pabyNoData == nullptr)
    2545             :         {
    2546          44 :             m_pabyNoData = static_cast<GByte *>(CPLMalloc(nSize));
    2547             :         }
    2548          47 :         memset(m_pabyNoData, 0, nSize);
    2549          47 :         GDALExtendedDataType::CopyValue(pNoData, m_oType, m_pabyNoData,
    2550          47 :                                         m_oType);
    2551             :     }
    2552          48 :     return true;
    2553             : }
    2554             : 
    2555             : /************************************************************************/
    2556             : /*                            GetAttribute()                            */
    2557             : /************************************************************************/
    2558             : 
    2559             : std::shared_ptr<GDALAttribute>
    2560         284 : MEMMDArray::GetAttribute(const std::string &osName) const
    2561             : {
    2562         284 :     if (!CheckValidAndErrorOutIfNot())
    2563           0 :         return nullptr;
    2564         284 :     auto oIter = m_oMapAttributes.find(osName);
    2565         284 :     if (oIter != m_oMapAttributes.end())
    2566          70 :         return oIter->second;
    2567         214 :     return nullptr;
    2568             : }
    2569             : 
    2570             : /************************************************************************/
    2571             : /*                           GetAttributes()                            */
    2572             : /************************************************************************/
    2573             : 
    2574             : std::vector<std::shared_ptr<GDALAttribute>>
    2575          63 : MEMMDArray::GetAttributes(CSLConstList) const
    2576             : {
    2577          63 :     if (!CheckValidAndErrorOutIfNot())
    2578           2 :         return {};
    2579         122 :     std::vector<std::shared_ptr<GDALAttribute>> oRes;
    2580          95 :     for (const auto &oIter : m_oMapAttributes)
    2581             :     {
    2582          34 :         oRes.push_back(oIter.second);
    2583             :     }
    2584          61 :     return oRes;
    2585             : }
    2586             : 
    2587             : /************************************************************************/
    2588             : /*                          CreateAttribute()                           */
    2589             : /************************************************************************/
    2590             : 
    2591             : std::shared_ptr<GDALAttribute>
    2592          62 : MEMMDArray::CreateAttribute(const std::string &osName,
    2593             :                             const std::vector<GUInt64> &anDimensions,
    2594             :                             const GDALExtendedDataType &oDataType, CSLConstList)
    2595             : {
    2596          62 :     if (!CheckValidAndErrorOutIfNot())
    2597           0 :         return nullptr;
    2598          62 :     if (osName.empty())
    2599             :     {
    2600           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    2601             :                  "Empty attribute name not supported");
    2602           1 :         return nullptr;
    2603             :     }
    2604          61 :     if (m_oMapAttributes.find(osName) != m_oMapAttributes.end())
    2605             :     {
    2606           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2607             :                  "An attribute with same name already exists");
    2608           0 :         return nullptr;
    2609             :     }
    2610         122 :     auto poSelf = std::dynamic_pointer_cast<MEMMDArray>(m_pSelf.lock());
    2611          61 :     CPLAssert(poSelf);
    2612         122 :     auto newAttr(MEMAttribute::Create(poSelf, osName, anDimensions, oDataType));
    2613          61 :     if (!newAttr)
    2614           0 :         return nullptr;
    2615          61 :     m_oMapAttributes[osName] = newAttr;
    2616          61 :     return newAttr;
    2617             : }
    2618             : 
    2619             : /************************************************************************/
    2620             : /*                          DeleteAttribute()                           */
    2621             : /************************************************************************/
    2622             : 
    2623           4 : bool MEMMDArray::DeleteAttribute(const std::string &osName,
    2624             :                                  CSLConstList /*papszOptions*/)
    2625             : {
    2626           4 :     if (!CheckValidAndErrorOutIfNot())
    2627           0 :         return false;
    2628           4 :     auto oIter = m_oMapAttributes.find(osName);
    2629           4 :     if (oIter == m_oMapAttributes.end())
    2630             :     {
    2631           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    2632             :                  "Attribute %s is not an attribute of this array",
    2633             :                  osName.c_str());
    2634           1 :         return false;
    2635             :     }
    2636             : 
    2637           3 :     oIter->second->Deleted();
    2638           3 :     m_oMapAttributes.erase(oIter);
    2639           3 :     return true;
    2640             : }
    2641             : 
    2642             : /************************************************************************/
    2643             : /*                       GetCoordinateVariables()                       */
    2644             : /************************************************************************/
    2645             : 
    2646             : std::vector<std::shared_ptr<GDALMDArray>>
    2647          23 : MEMMDArray::GetCoordinateVariables() const
    2648             : {
    2649          23 :     if (!CheckValidAndErrorOutIfNot())
    2650           0 :         return {};
    2651          46 :     std::vector<std::shared_ptr<GDALMDArray>> ret;
    2652          69 :     const auto poCoordinates = GetAttribute("coordinates");
    2653          11 :     if (poCoordinates &&
    2654          34 :         poCoordinates->GetDataType().GetClass() == GEDTC_STRING &&
    2655          11 :         poCoordinates->GetDimensionCount() == 0)
    2656             :     {
    2657          11 :         const char *pszCoordinates = poCoordinates->ReadAsString();
    2658          11 :         if (pszCoordinates)
    2659             :         {
    2660          22 :             auto poGroup = m_poGroupWeak.lock();
    2661          11 :             if (!poGroup)
    2662             :             {
    2663           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2664             :                          "Cannot access coordinate variables of %s has "
    2665             :                          "belonging group has gone out of scope",
    2666           0 :                          GetName().c_str());
    2667             :             }
    2668             :             else
    2669             :             {
    2670             :                 const CPLStringList aosNames(
    2671          22 :                     CSLTokenizeString2(pszCoordinates, " ", 0));
    2672          41 :                 for (int i = 0; i < aosNames.size(); i++)
    2673             :                 {
    2674          90 :                     auto poCoordinateVar = poGroup->OpenMDArray(aosNames[i]);
    2675          30 :                     if (poCoordinateVar)
    2676             :                     {
    2677          29 :                         ret.emplace_back(poCoordinateVar);
    2678             :                     }
    2679             :                     else
    2680             :                     {
    2681           1 :                         CPLError(CE_Warning, CPLE_AppDefined,
    2682             :                                  "Cannot find variable corresponding to "
    2683             :                                  "coordinate %s",
    2684             :                                  aosNames[i]);
    2685             :                     }
    2686             :                 }
    2687             :             }
    2688             :         }
    2689             :     }
    2690             : 
    2691          23 :     return ret;
    2692             : }
    2693             : 
    2694             : /************************************************************************/
    2695             : /*                               Resize()                               */
    2696             : /************************************************************************/
    2697             : 
    2698          17 : bool MEMMDArray::Resize(const std::vector<GUInt64> &anNewDimSizes,
    2699             :                         CSLConstList /* papszOptions */)
    2700             : {
    2701          17 :     return Resize(anNewDimSizes, /*bResizeOtherArrays=*/true);
    2702             : }
    2703             : 
    2704          21 : bool MEMMDArray::Resize(const std::vector<GUInt64> &anNewDimSizes,
    2705             :                         bool bResizeOtherArrays)
    2706             : {
    2707          21 :     if (!CheckValidAndErrorOutIfNot())
    2708           0 :         return false;
    2709          21 :     if (!IsWritable())
    2710             :     {
    2711           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2712             :                  "Resize() not supported on read-only file");
    2713           0 :         return false;
    2714             :     }
    2715          21 :     if (!m_bOwnArray)
    2716             :     {
    2717           0 :         CPLError(
    2718             :             CE_Failure, CPLE_AppDefined,
    2719             :             "Resize() not supported on an array that does not own its memory");
    2720           0 :         return false;
    2721             :     }
    2722             : 
    2723          21 :     const auto nDimCount = GetDimensionCount();
    2724          21 :     if (anNewDimSizes.size() != nDimCount)
    2725             :     {
    2726           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
    2727             :                  "Not expected number of values in anNewDimSizes.");
    2728           0 :         return false;
    2729             :     }
    2730             : 
    2731          21 :     auto &dims = GetDimensions();
    2732          42 :     std::vector<size_t> anDecreasedDimIdx;
    2733          42 :     std::vector<size_t> anGrownDimIdx;
    2734          42 :     std::map<GDALDimension *, GUInt64> oMapDimToSize;
    2735          61 :     for (size_t i = 0; i < nDimCount; ++i)
    2736             :     {
    2737          43 :         auto oIter = oMapDimToSize.find(dims[i].get());
    2738          43 :         if (oIter != oMapDimToSize.end() && oIter->second != anNewDimSizes[i])
    2739             :         {
    2740           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    2741             :                      "Cannot resize a dimension referenced several times "
    2742             :                      "to different sizes");
    2743           3 :             return false;
    2744             :         }
    2745          41 :         if (anNewDimSizes[i] != dims[i]->GetSize())
    2746             :         {
    2747          22 :             if (anNewDimSizes[i] == 0)
    2748             :             {
    2749           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    2750             :                          "Illegal dimension size 0");
    2751           1 :                 return false;
    2752             :             }
    2753          21 :             auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
    2754          21 :             if (!dim)
    2755             :             {
    2756           0 :                 CPLError(
    2757             :                     CE_Failure, CPLE_AppDefined,
    2758             :                     "Cannot resize a dimension that is not a MEMDimension");
    2759           0 :                 return false;
    2760             :             }
    2761          21 :             oMapDimToSize[dim.get()] = anNewDimSizes[i];
    2762          21 :             if (anNewDimSizes[i] < dims[i]->GetSize())
    2763             :             {
    2764           7 :                 anDecreasedDimIdx.push_back(i);
    2765             :             }
    2766             :             else
    2767             :             {
    2768          14 :                 anGrownDimIdx.push_back(i);
    2769             :             }
    2770             :         }
    2771             :         else
    2772             :         {
    2773          19 :             oMapDimToSize[dims[i].get()] = dims[i]->GetSize();
    2774             :         }
    2775             :     }
    2776             : 
    2777         132 :     const auto ResizeOtherArrays = [this, &anNewDimSizes, nDimCount, &dims]()
    2778             :     {
    2779          20 :         std::set<MEMMDArray *> oSetArrays;
    2780          10 :         std::map<GDALDimension *, GUInt64> oMapNewSize;
    2781          30 :         for (size_t i = 0; i < nDimCount; ++i)
    2782             :         {
    2783          20 :             if (anNewDimSizes[i] != dims[i]->GetSize())
    2784             :             {
    2785          24 :                 auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
    2786          12 :                 if (!dim)
    2787             :                 {
    2788           0 :                     CPLAssert(false);
    2789             :                 }
    2790             :                 else
    2791             :                 {
    2792          12 :                     oMapNewSize[dims[i].get()] = anNewDimSizes[i];
    2793          28 :                     for (const auto &poArray : dim->GetUsingArrays())
    2794             :                     {
    2795          16 :                         if (poArray != this)
    2796           4 :                             oSetArrays.insert(poArray);
    2797             :                     }
    2798             :                 }
    2799             :             }
    2800             :         }
    2801             : 
    2802          10 :         bool bOK = true;
    2803          14 :         for (auto *poArray : oSetArrays)
    2804             :         {
    2805           4 :             const auto &apoOtherDims = poArray->GetDimensions();
    2806             :             std::vector<GUInt64> anOtherArrayNewDimSizes(
    2807           4 :                 poArray->GetDimensionCount());
    2808          14 :             for (size_t i = 0; i < anOtherArrayNewDimSizes.size(); ++i)
    2809             :             {
    2810          10 :                 auto oIter = oMapNewSize.find(apoOtherDims[i].get());
    2811          10 :                 if (oIter != oMapNewSize.end())
    2812           4 :                     anOtherArrayNewDimSizes[i] = oIter->second;
    2813             :                 else
    2814           6 :                     anOtherArrayNewDimSizes[i] = apoOtherDims[i]->GetSize();
    2815             :             }
    2816           4 :             if (!poArray->Resize(anOtherArrayNewDimSizes,
    2817             :                                  /*bResizeOtherArrays=*/false))
    2818             :             {
    2819           0 :                 bOK = false;
    2820           0 :                 break;
    2821             :             }
    2822             :         }
    2823          10 :         if (!bOK)
    2824             :         {
    2825           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2826             :                      "Resizing of another array referencing the same dimension "
    2827             :                      "as one modified on the current array failed. All arrays "
    2828             :                      "referencing that dimension will be invalidated.");
    2829           0 :             Invalidate();
    2830           0 :             for (auto *poArray : oSetArrays)
    2831             :             {
    2832           0 :                 poArray->Invalidate();
    2833             :             }
    2834             :         }
    2835             : 
    2836          20 :         return bOK;
    2837          18 :     };
    2838             : 
    2839             :     // Decrease slowest varying dimension
    2840          24 :     if (anGrownDimIdx.empty() && anDecreasedDimIdx.size() == 1 &&
    2841           6 :         anDecreasedDimIdx[0] == 0)
    2842             :     {
    2843           4 :         CPLAssert(m_nTotalSize % dims[0]->GetSize() == 0);
    2844           4 :         const size_t nNewTotalSize = static_cast<size_t>(
    2845           4 :             (m_nTotalSize / dims[0]->GetSize()) * anNewDimSizes[0]);
    2846           4 :         if (m_oType.NeedsFreeDynamicMemory())
    2847             :         {
    2848           0 :             GByte *pabyPtr = m_pabyArray + nNewTotalSize;
    2849           0 :             GByte *pabyEnd = m_pabyArray + m_nTotalSize;
    2850           0 :             const auto nDTSize(m_oType.GetSize());
    2851           0 :             while (pabyPtr < pabyEnd)
    2852             :             {
    2853           0 :                 m_oType.FreeDynamicMemory(pabyPtr);
    2854           0 :                 pabyPtr += nDTSize;
    2855             :             }
    2856             :         }
    2857             :         // shrinking... cannot fail, and even if it does, that's ok
    2858             :         GByte *pabyArray = static_cast<GByte *>(
    2859           4 :             VSI_REALLOC_VERBOSE(m_pabyArray, nNewTotalSize));
    2860           4 :         if (pabyArray)
    2861           4 :             m_pabyArray = pabyArray;
    2862           4 :         m_nTotalSize = nNewTotalSize;
    2863             : 
    2864           4 :         if (bResizeOtherArrays)
    2865             :         {
    2866           3 :             if (!ResizeOtherArrays())
    2867           0 :                 return false;
    2868             : 
    2869           6 :             auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[0]);
    2870           3 :             if (dim)
    2871             :             {
    2872           3 :                 dim->SetSize(anNewDimSizes[0]);
    2873             :             }
    2874             :             else
    2875             :             {
    2876           0 :                 CPLAssert(false);
    2877             :             }
    2878             :         }
    2879           4 :         return true;
    2880             :     }
    2881             : 
    2882             :     // Increase slowest varying dimension
    2883          24 :     if (anDecreasedDimIdx.empty() && anGrownDimIdx.size() == 1 &&
    2884          10 :         anGrownDimIdx[0] == 0)
    2885             :     {
    2886           6 :         CPLAssert(m_nTotalSize % dims[0]->GetSize() == 0);
    2887           6 :         GUInt64 nNewTotalSize64 = m_nTotalSize / dims[0]->GetSize();
    2888           6 :         if (nNewTotalSize64 >
    2889           6 :             std::numeric_limits<GUInt64>::max() / anNewDimSizes[0])
    2890             :         {
    2891           1 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
    2892           1 :             return false;
    2893             :         }
    2894           5 :         nNewTotalSize64 *= anNewDimSizes[0];
    2895             :         // We restrict the size of the allocation so that all elements can be
    2896             :         // indexed by GPtrDiff_t
    2897           5 :         if (nNewTotalSize64 >
    2898           5 :             static_cast<size_t>(std::numeric_limits<GPtrDiff_t>::max()))
    2899             :         {
    2900           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
    2901           0 :             return false;
    2902             :         }
    2903           5 :         const size_t nNewTotalSize = static_cast<size_t>(nNewTotalSize64);
    2904             :         GByte *pabyArray = static_cast<GByte *>(
    2905           5 :             VSI_REALLOC_VERBOSE(m_pabyArray, nNewTotalSize));
    2906           5 :         if (!pabyArray)
    2907           1 :             return false;
    2908           4 :         memset(pabyArray + m_nTotalSize, 0, nNewTotalSize - m_nTotalSize);
    2909           4 :         m_pabyArray = pabyArray;
    2910           4 :         m_nTotalSize = nNewTotalSize;
    2911             : 
    2912           4 :         if (bResizeOtherArrays)
    2913             :         {
    2914           3 :             if (!ResizeOtherArrays())
    2915           0 :                 return false;
    2916             : 
    2917           6 :             auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[0]);
    2918           3 :             if (dim)
    2919             :             {
    2920           3 :                 dim->SetSize(anNewDimSizes[0]);
    2921             :             }
    2922             :             else
    2923             :             {
    2924           0 :                 CPLAssert(false);
    2925             :             }
    2926             :         }
    2927           4 :         return true;
    2928             :     }
    2929             : 
    2930             :     // General case where we modify other dimensions that the first one.
    2931             : 
    2932             :     // Create dummy dimensions at the new sizes
    2933          16 :     std::vector<std::shared_ptr<GDALDimension>> aoNewDims;
    2934          30 :     for (size_t i = 0; i < nDimCount; ++i)
    2935             :     {
    2936          44 :         aoNewDims.emplace_back(std::make_shared<MEMDimension>(
    2937          44 :             std::string(), dims[i]->GetName(), std::string(), std::string(),
    2938          44 :             anNewDimSizes[i]));
    2939             :     }
    2940             : 
    2941             :     // Create a temporary array
    2942             :     auto poTempMDArray =
    2943          24 :         Create(std::string(), std::string(), aoNewDims, GetDataType());
    2944           8 :     if (!poTempMDArray->Init())
    2945           2 :         return false;
    2946          12 :     std::vector<GUInt64> arrayStartIdx(nDimCount);
    2947          12 :     std::vector<size_t> count(nDimCount);
    2948          12 :     std::vector<GInt64> arrayStep(nDimCount, 1);
    2949          12 :     std::vector<GPtrDiff_t> bufferStride(nDimCount);
    2950          22 :     for (size_t i = nDimCount; i > 0;)
    2951             :     {
    2952          16 :         --i;
    2953          16 :         if (i == nDimCount - 1)
    2954           6 :             bufferStride[i] = 1;
    2955             :         else
    2956             :         {
    2957          20 :             bufferStride[i] = static_cast<GPtrDiff_t>(bufferStride[i + 1] *
    2958          10 :                                                       dims[i + 1]->GetSize());
    2959             :         }
    2960          16 :         const auto nCount = std::min(anNewDimSizes[i], dims[i]->GetSize());
    2961          16 :         count[i] = static_cast<size_t>(nCount);
    2962             :     }
    2963             :     // Copy the current content into the array with the new layout
    2964          12 :     if (!poTempMDArray->Write(arrayStartIdx.data(), count.data(),
    2965           6 :                               arrayStep.data(), bufferStride.data(),
    2966           6 :                               GetDataType(), m_pabyArray))
    2967             :     {
    2968           0 :         return false;
    2969             :     }
    2970             : 
    2971             :     // Move content of the temporary array into the current array, and
    2972             :     // invalidate the temporary array
    2973           6 :     FreeArray();
    2974           6 :     m_bOwnArray = true;
    2975           6 :     m_pabyArray = poTempMDArray->m_pabyArray;
    2976           6 :     m_nTotalSize = poTempMDArray->m_nTotalSize;
    2977           6 :     m_anStrides = poTempMDArray->m_anStrides;
    2978             : 
    2979           6 :     poTempMDArray->m_bOwnArray = false;
    2980           6 :     poTempMDArray->m_pabyArray = nullptr;
    2981           6 :     poTempMDArray->m_nTotalSize = 0;
    2982             : 
    2983           6 :     if (bResizeOtherArrays && !ResizeOtherArrays())
    2984           0 :         return false;
    2985             : 
    2986             :     // Update dimension size
    2987          22 :     for (size_t i = 0; i < nDimCount; ++i)
    2988             :     {
    2989          16 :         if (anNewDimSizes[i] != dims[i]->GetSize())
    2990             :         {
    2991          10 :             auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
    2992           5 :             if (dim)
    2993             :             {
    2994           5 :                 dim->SetSize(anNewDimSizes[i]);
    2995             :             }
    2996             :             else
    2997             :             {
    2998           0 :                 CPLAssert(false);
    2999             :             }
    3000             :         }
    3001             :     }
    3002             : 
    3003           6 :     return true;
    3004             : }
    3005             : 
    3006             : /************************************************************************/
    3007             : /*                               Rename()                               */
    3008             : /************************************************************************/
    3009             : 
    3010           3 : bool MEMMDArray::Rename(const std::string &osNewName)
    3011             : {
    3012           3 :     if (!CheckValidAndErrorOutIfNot())
    3013           0 :         return false;
    3014           3 :     if (osNewName.empty())
    3015             :     {
    3016           1 :         CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
    3017           1 :         return false;
    3018             :     }
    3019             : 
    3020           2 :     if (auto poParentGroup =
    3021           4 :             std::dynamic_pointer_cast<MEMGroup>(m_poGroupWeak.lock()))
    3022             :     {
    3023           2 :         if (!poParentGroup->RenameArray(m_osName, osNewName))
    3024             :         {
    3025           1 :             return false;
    3026             :         }
    3027             :     }
    3028             : 
    3029           1 :     BaseRename(osNewName);
    3030             : 
    3031           1 :     return true;
    3032             : }
    3033             : 
    3034             : /************************************************************************/
    3035             : /*                      NotifyChildrenOfRenaming()                      */
    3036             : /************************************************************************/
    3037             : 
    3038           3 : void MEMMDArray::NotifyChildrenOfRenaming()
    3039             : {
    3040           6 :     for (const auto &oIter : m_oMapAttributes)
    3041           3 :         oIter.second->ParentRenamed(m_osFullName);
    3042           3 : }
    3043             : 
    3044             : /************************************************************************/
    3045             : /*                      NotifyChildrenOfDeletion()                      */
    3046             : /************************************************************************/
    3047             : 
    3048           2 : void MEMMDArray::NotifyChildrenOfDeletion()
    3049             : {
    3050           4 :     for (const auto &oIter : m_oMapAttributes)
    3051           2 :         oIter.second->ParentDeleted();
    3052           2 : }
    3053             : 
    3054             : /************************************************************************/
    3055             : /*                          BuildDimensions()                           */
    3056             : /************************************************************************/
    3057             : 
    3058             : static std::vector<std::shared_ptr<GDALDimension>>
    3059        1715 : BuildDimensions(const std::vector<GUInt64> &anDimensions)
    3060             : {
    3061        1715 :     std::vector<std::shared_ptr<GDALDimension>> res;
    3062        1963 :     for (size_t i = 0; i < anDimensions.size(); i++)
    3063             :     {
    3064         496 :         res.emplace_back(std::make_shared<GDALDimensionWeakIndexingVar>(
    3065         496 :             std::string(), CPLSPrintf("dim%u", static_cast<unsigned>(i)),
    3066         744 :             std::string(), std::string(), anDimensions[i]));
    3067             :     }
    3068        1715 :     return res;
    3069             : }
    3070             : 
    3071             : /************************************************************************/
    3072             : /*                            MEMAttribute()                            */
    3073             : /************************************************************************/
    3074             : 
    3075        1715 : MEMAttribute::MEMAttribute(const std::string &osParentName,
    3076             :                            const std::string &osName,
    3077             :                            const std::vector<GUInt64> &anDimensions,
    3078        1715 :                            const GDALExtendedDataType &oType)
    3079             :     : GDALAbstractMDArray(osParentName, osName),
    3080        1715 :       MEMAbstractMDArray(osParentName, osName, BuildDimensions(anDimensions),
    3081             :                          oType),
    3082        3430 :       GDALAttribute(osParentName, osName)
    3083             : {
    3084        1715 : }
    3085             : 
    3086             : /************************************************************************/
    3087             : /*                        MEMAttribute::Create()                        */
    3088             : /************************************************************************/
    3089             : 
    3090             : std::shared_ptr<MEMAttribute>
    3091        1715 : MEMAttribute::Create(const std::string &osParentName, const std::string &osName,
    3092             :                      const std::vector<GUInt64> &anDimensions,
    3093             :                      const GDALExtendedDataType &oType)
    3094             : {
    3095             :     auto attr(std::shared_ptr<MEMAttribute>(
    3096        3430 :         new MEMAttribute(osParentName, osName, anDimensions, oType)));
    3097        1715 :     attr->SetSelf(attr);
    3098        1715 :     if (!attr->Init())
    3099           0 :         return nullptr;
    3100        1715 :     return attr;
    3101             : }
    3102             : 
    3103             : /************************************************************************/
    3104             : /*                        MEMAttribute::Create()                        */
    3105             : /************************************************************************/
    3106             : 
    3107        1581 : std::shared_ptr<MEMAttribute> MEMAttribute::Create(
    3108             :     const std::shared_ptr<MEMGroup> &poParentGroup, const std::string &osName,
    3109             :     const std::vector<GUInt64> &anDimensions, const GDALExtendedDataType &oType)
    3110             : {
    3111             :     const std::string osParentName =
    3112        1581 :         (poParentGroup && poParentGroup->GetName().empty())
    3113        1581 :             ?
    3114             :             // Case of the ZarrAttributeGroup::m_oGroup fake group
    3115        1037 :             poParentGroup->GetFullName()
    3116        1088 :             : ((poParentGroup == nullptr || poParentGroup->GetFullName() == "/"
    3117        3213 :                     ? "/"
    3118          10 :                     : poParentGroup->GetFullName() + "/") +
    3119        4743 :                "_GLOBAL_");
    3120        3162 :     auto attr(Create(osParentName, osName, anDimensions, oType));
    3121        1581 :     if (!attr)
    3122           0 :         return nullptr;
    3123        1581 :     attr->m_poParent = poParentGroup;
    3124        1581 :     return attr;
    3125             : }
    3126             : 
    3127             : /************************************************************************/
    3128             : /*                        MEMAttribute::Create()                        */
    3129             : /************************************************************************/
    3130             : 
    3131          61 : std::shared_ptr<MEMAttribute> MEMAttribute::Create(
    3132             :     const std::shared_ptr<MEMMDArray> &poParentArray, const std::string &osName,
    3133             :     const std::vector<GUInt64> &anDimensions, const GDALExtendedDataType &oType)
    3134             : {
    3135             :     auto attr(
    3136         122 :         Create(poParentArray->GetFullName(), osName, anDimensions, oType));
    3137          61 :     if (!attr)
    3138           0 :         return nullptr;
    3139          61 :     attr->m_poParent = poParentArray;
    3140          61 :     return attr;
    3141             : }
    3142             : 
    3143             : /************************************************************************/
    3144             : /*                               Rename()                               */
    3145             : /************************************************************************/
    3146             : 
    3147          19 : bool MEMAttribute::Rename(const std::string &osNewName)
    3148             : {
    3149          19 :     if (!CheckValidAndErrorOutIfNot())
    3150           8 :         return false;
    3151          11 :     if (osNewName.empty())
    3152             :     {
    3153           1 :         CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
    3154           1 :         return false;
    3155             :     }
    3156             : 
    3157          10 :     if (auto poParent = m_poParent.lock())
    3158             :     {
    3159          10 :         if (!poParent->RenameAttribute(m_osName, osNewName))
    3160             :         {
    3161           2 :             return false;
    3162             :         }
    3163             :     }
    3164             : 
    3165           8 :     BaseRename(osNewName);
    3166             : 
    3167           8 :     m_bModified = true;
    3168             : 
    3169           8 :     return true;
    3170             : }
    3171             : 
    3172             : /************************************************************************/
    3173             : /*                            MEMDimension()                            */
    3174             : /************************************************************************/
    3175             : 
    3176         422 : MEMDimension::MEMDimension(const std::string &osParentName,
    3177             :                            const std::string &osName, const std::string &osType,
    3178         422 :                            const std::string &osDirection, GUInt64 nSize)
    3179             :     : GDALDimensionWeakIndexingVar(osParentName, osName, osType, osDirection,
    3180         422 :                                    nSize)
    3181             : {
    3182         422 : }
    3183             : 
    3184             : /************************************************************************/
    3185             : /*                         RegisterUsingArray()                         */
    3186             : /************************************************************************/
    3187             : 
    3188         520 : void MEMDimension::RegisterUsingArray(MEMMDArray *poArray)
    3189             : {
    3190         520 :     m_oSetArrays.insert(poArray);
    3191         520 : }
    3192             : 
    3193             : /************************************************************************/
    3194             : /*                        UnRegisterUsingArray()                        */
    3195             : /************************************************************************/
    3196             : 
    3197         536 : void MEMDimension::UnRegisterUsingArray(MEMMDArray *poArray)
    3198             : {
    3199         536 :     m_oSetArrays.erase(poArray);
    3200         536 : }
    3201             : 
    3202             : /************************************************************************/
    3203             : /*                               Create()                               */
    3204             : /************************************************************************/
    3205             : 
    3206             : /* static */
    3207             : std::shared_ptr<MEMDimension>
    3208         400 : MEMDimension::Create(const std::shared_ptr<MEMGroup> &poParentGroup,
    3209             :                      const std::string &osName, const std::string &osType,
    3210             :                      const std::string &osDirection, GUInt64 nSize)
    3211             : {
    3212             :     auto newDim(std::make_shared<MEMDimension>(
    3213         400 :         poParentGroup->GetFullName(), osName, osType, osDirection, nSize));
    3214         400 :     newDim->m_poParentGroup = poParentGroup;
    3215         400 :     return newDim;
    3216             : }
    3217             : 
    3218             : /************************************************************************/
    3219             : /*                          CreateDimension()                           */
    3220             : /************************************************************************/
    3221             : 
    3222             : std::shared_ptr<GDALDimension>
    3223         402 : MEMGroup::CreateDimension(const std::string &osName, const std::string &osType,
    3224             :                           const std::string &osDirection, GUInt64 nSize,
    3225             :                           CSLConstList)
    3226             : {
    3227         402 :     if (osName.empty())
    3228             :     {
    3229           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    3230             :                  "Empty dimension name not supported");
    3231           1 :         return nullptr;
    3232             :     }
    3233         401 :     if (m_oMapDimensions.find(osName) != m_oMapDimensions.end())
    3234             :     {
    3235           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    3236             :                  "A dimension with same name already exists");
    3237           1 :         return nullptr;
    3238             :     }
    3239             :     auto newDim(MEMDimension::Create(
    3240         800 :         std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()), osName, osType,
    3241         800 :         osDirection, nSize));
    3242         400 :     m_oMapDimensions[osName] = newDim;
    3243         400 :     return newDim;
    3244             : }
    3245             : 
    3246             : /************************************************************************/
    3247             : /*                               Rename()                               */
    3248             : /************************************************************************/
    3249             : 
    3250           3 : bool MEMDimension::Rename(const std::string &osNewName)
    3251             : {
    3252           3 :     if (osNewName.empty())
    3253             :     {
    3254           1 :         CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
    3255           1 :         return false;
    3256             :     }
    3257             : 
    3258           2 :     if (auto poParentGroup = m_poParentGroup.lock())
    3259             :     {
    3260           2 :         if (!poParentGroup->RenameDimension(m_osName, osNewName))
    3261             :         {
    3262           1 :             return false;
    3263             :         }
    3264             :     }
    3265             : 
    3266           1 :     BaseRename(osNewName);
    3267             : 
    3268           1 :     return true;
    3269             : }
    3270             : 
    3271             : /************************************************************************/
    3272             : /*                       CreateMultiDimensional()                       */
    3273             : /************************************************************************/
    3274             : 
    3275             : GDALDataset *
    3276         220 : MEMDataset::CreateMultiDimensional(const char *pszFilename,
    3277             :                                    CSLConstList /*papszRootGroupOptions*/,
    3278             :                                    CSLConstList /*papszOptions*/)
    3279             : {
    3280         220 :     auto poDS = new MEMDataset();
    3281             : 
    3282         220 :     poDS->SetDescription(pszFilename);
    3283         220 :     auto poRootGroup = MEMGroup::Create(std::string(), nullptr);
    3284         220 :     poDS->m_poPrivate->m_poRootGroup = poRootGroup;
    3285             : 
    3286         440 :     return poDS;
    3287             : }
    3288             : 
    3289             : /************************************************************************/
    3290             : /*                            GetRootGroup()                            */
    3291             : /************************************************************************/
    3292             : 
    3293        8377 : std::shared_ptr<GDALGroup> MEMDataset::GetRootGroup() const
    3294             : {
    3295        8377 :     return m_poPrivate->m_poRootGroup;
    3296             : }
    3297             : 
    3298             : /************************************************************************/
    3299             : /*                         MEMDatasetIdentify()                         */
    3300             : /************************************************************************/
    3301             : 
    3302       79819 : static int MEMDatasetIdentify(GDALOpenInfo *poOpenInfo)
    3303             : {
    3304       79832 :     return (STARTS_WITH(poOpenInfo->pszFilename, "MEM:::") &&
    3305       79832 :             poOpenInfo->fpL == nullptr);
    3306             : }
    3307             : 
    3308             : /************************************************************************/
    3309             : /*                          MEMDatasetDelete()                          */
    3310             : /************************************************************************/
    3311             : 
    3312           5 : static CPLErr MEMDatasetDelete(const char * /* fileName */)
    3313             : {
    3314             :     /* Null implementation, so that people can Delete("MEM:::") */
    3315           5 :     return CE_None;
    3316             : }
    3317             : 
    3318             : /************************************************************************/
    3319             : /*                            CreateLayer()                             */
    3320             : /************************************************************************/
    3321             : 
    3322           0 : OGRMemLayer *MEMDataset::CreateLayer(const OGRFeatureDefn &oDefn,
    3323             :                                      CSLConstList papszOptions)
    3324             : {
    3325           0 :     auto poLayer = std::make_unique<OGRMemLayer>(oDefn);
    3326             : 
    3327           0 :     if (CPLFetchBool(papszOptions, "ADVERTIZE_UTF8", false))
    3328           0 :         poLayer->SetAdvertizeUTF8(true);
    3329             : 
    3330           0 :     poLayer->SetDataset(this);
    3331           0 :     poLayer->SetFIDColumn(CSLFetchNameValueDef(papszOptions, "FID", ""));
    3332             : 
    3333             :     // Add layer to data source layer list.
    3334           0 :     m_apoLayers.emplace_back(std::move(poLayer));
    3335           0 :     return m_apoLayers.back().get();
    3336             : }
    3337             : 
    3338             : /************************************************************************/
    3339             : /*                            ICreateLayer()                            */
    3340             : /************************************************************************/
    3341             : 
    3342        2082 : OGRLayer *MEMDataset::ICreateLayer(const char *pszLayerName,
    3343             :                                    const OGRGeomFieldDefn *poGeomFieldDefn,
    3344             :                                    CSLConstList papszOptions)
    3345             : {
    3346             :     // Create the layer object.
    3347             : 
    3348        2082 :     const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
    3349             :     const auto poSRSIn =
    3350        2082 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
    3351             : 
    3352        2082 :     OGRSpatialReference *poSRS = nullptr;
    3353        2082 :     if (poSRSIn)
    3354             :     {
    3355         390 :         poSRS = poSRSIn->Clone();
    3356         390 :         poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    3357             :     }
    3358        4164 :     auto poLayer = std::make_unique<OGRMemLayer>(pszLayerName, poSRS, eType);
    3359        2082 :     if (poSRS)
    3360             :     {
    3361         390 :         poSRS->Release();
    3362             :     }
    3363             : 
    3364        2082 :     if (CPLFetchBool(papszOptions, "ADVERTIZE_UTF8", false))
    3365          35 :         poLayer->SetAdvertizeUTF8(true);
    3366             : 
    3367        2082 :     poLayer->SetDataset(this);
    3368        2082 :     poLayer->SetFIDColumn(CSLFetchNameValueDef(papszOptions, "FID", ""));
    3369             : 
    3370             :     // Add layer to data source layer list.
    3371        2082 :     m_apoLayers.emplace_back(std::move(poLayer));
    3372        4164 :     return m_apoLayers.back().get();
    3373             : }
    3374             : 
    3375             : /************************************************************************/
    3376             : /*                            DeleteLayer()                             */
    3377             : /************************************************************************/
    3378             : 
    3379           9 : OGRErr MEMDataset::DeleteLayer(int iLayer)
    3380             : 
    3381             : {
    3382           9 :     if (iLayer >= 0 && iLayer < static_cast<int>(m_apoLayers.size()))
    3383             :     {
    3384           7 :         m_apoLayers.erase(m_apoLayers.begin() + iLayer);
    3385           7 :         return OGRERR_NONE;
    3386             :     }
    3387             : 
    3388           2 :     return OGRERR_FAILURE;
    3389             : }
    3390             : 
    3391             : /************************************************************************/
    3392             : /*                           TestCapability()                           */
    3393             : /************************************************************************/
    3394             : 
    3395        1451 : int MEMDataset::TestCapability(const char *pszCap) const
    3396             : 
    3397             : {
    3398        1451 :     if (EQUAL(pszCap, ODsCCreateLayer) || EQUAL(pszCap, ODsCDeleteLayer) ||
    3399         981 :         EQUAL(pszCap, ODsCCreateGeomFieldAfterCreateLayer) ||
    3400         614 :         EQUAL(pszCap, ODsCCurveGeometries) ||
    3401         587 :         EQUAL(pszCap, ODsCMeasuredGeometries) ||
    3402         587 :         EQUAL(pszCap, ODsCZGeometries) || EQUAL(pszCap, ODsCRandomLayerWrite) ||
    3403         574 :         EQUAL(pszCap, ODsCAddFieldDomain) ||
    3404         564 :         EQUAL(pszCap, ODsCDeleteFieldDomain) ||
    3405         564 :         EQUAL(pszCap, ODsCUpdateFieldDomain) ||
    3406         564 :         EQUAL(pszCap, GDsCAddRelationship) ||
    3407         563 :         EQUAL(pszCap, GDsCDeleteRelationship) ||
    3408         562 :         EQUAL(pszCap, GDsCUpdateRelationship))
    3409             :     {
    3410         890 :         return true;
    3411             :     }
    3412             : 
    3413         561 :     return GDALDataset::TestCapability(pszCap);
    3414             : }
    3415             : 
    3416             : /************************************************************************/
    3417             : /*                              GetLayer()                              */
    3418             : /************************************************************************/
    3419             : 
    3420        8373 : const OGRLayer *MEMDataset::GetLayer(int iLayer) const
    3421             : 
    3422             : {
    3423        8373 :     if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
    3424          10 :         return nullptr;
    3425             : 
    3426        8363 :     return m_apoLayers[iLayer].get();
    3427             : }
    3428             : 
    3429             : /************************************************************************/
    3430             : /*                           AddFieldDomain()                           */
    3431             : /************************************************************************/
    3432             : 
    3433          20 : bool MEMDataset::AddFieldDomain(std::unique_ptr<OGRFieldDomain> &&domain,
    3434             :                                 std::string &failureReason)
    3435             : {
    3436          20 :     if (GetFieldDomain(domain->GetName()) != nullptr)
    3437             :     {
    3438           1 :         failureReason = "A domain of identical name already exists";
    3439           1 :         return false;
    3440             :     }
    3441          19 :     const std::string domainName(domain->GetName());
    3442          19 :     m_oMapFieldDomains[domainName] = std::move(domain);
    3443          19 :     return true;
    3444             : }
    3445             : 
    3446             : /************************************************************************/
    3447             : /*                         DeleteFieldDomain()                          */
    3448             : /************************************************************************/
    3449             : 
    3450           6 : bool MEMDataset::DeleteFieldDomain(const std::string &name,
    3451             :                                    std::string &failureReason)
    3452             : {
    3453           6 :     const auto iter = m_oMapFieldDomains.find(name);
    3454           6 :     if (iter == m_oMapFieldDomains.end())
    3455             :     {
    3456           2 :         failureReason = "Domain does not exist";
    3457           2 :         return false;
    3458             :     }
    3459             : 
    3460           4 :     m_oMapFieldDomains.erase(iter);
    3461             : 
    3462           8 :     for (auto &poLayer : m_apoLayers)
    3463             :     {
    3464          10 :         for (int j = 0; j < poLayer->GetLayerDefn()->GetFieldCount(); ++j)
    3465             :         {
    3466           6 :             OGRLayer *poLayerAsLayer = poLayer.get();
    3467             :             OGRFieldDefn *poFieldDefn =
    3468           6 :                 poLayerAsLayer->GetLayerDefn()->GetFieldDefn(j);
    3469           6 :             if (poFieldDefn->GetDomainName() == name)
    3470             :             {
    3471           3 :                 whileUnsealing(poFieldDefn)->SetDomainName(std::string());
    3472             :             }
    3473             :         }
    3474             :     }
    3475             : 
    3476           4 :     return true;
    3477             : }
    3478             : 
    3479             : /************************************************************************/
    3480             : /*                         UpdateFieldDomain()                          */
    3481             : /************************************************************************/
    3482             : 
    3483           3 : bool MEMDataset::UpdateFieldDomain(std::unique_ptr<OGRFieldDomain> &&domain,
    3484             :                                    std::string &failureReason)
    3485             : {
    3486           6 :     const std::string domainName(domain->GetName());
    3487           3 :     const auto iter = m_oMapFieldDomains.find(domainName);
    3488           3 :     if (iter == m_oMapFieldDomains.end())
    3489             :     {
    3490           1 :         failureReason = "No matching domain found";
    3491           1 :         return false;
    3492             :     }
    3493           2 :     m_oMapFieldDomains[domainName] = std::move(domain);
    3494           2 :     return true;
    3495             : }
    3496             : 
    3497             : /************************************************************************/
    3498             : /*                        GetRelationshipNames()                        */
    3499             : /************************************************************************/
    3500             : 
    3501         217 : std::vector<std::string> MEMDataset::GetRelationshipNames(CSLConstList) const
    3502             : {
    3503         217 :     std::vector<std::string> ret;
    3504         218 :     for (const auto &kv : m_poPrivate->m_oMapRelationships)
    3505           1 :         ret.push_back(kv.first);
    3506         217 :     return ret;
    3507             : }
    3508             : 
    3509             : /************************************************************************/
    3510             : /*                          GetRelationship()                           */
    3511             : /************************************************************************/
    3512             : 
    3513             : const GDALRelationship *
    3514           4 : MEMDataset::GetRelationship(const std::string &name) const
    3515             : {
    3516           4 :     const auto iter = m_poPrivate->m_oMapRelationships.find(name);
    3517           4 :     if (iter != m_poPrivate->m_oMapRelationships.end())
    3518           2 :         return iter->second.get();
    3519           2 :     return nullptr;
    3520             : }
    3521             : 
    3522             : /************************************************************************/
    3523             : /*                          AddRelationship()                           */
    3524             : /************************************************************************/
    3525             : 
    3526           1 : bool MEMDataset::AddRelationship(
    3527             :     std::unique_ptr<GDALRelationship> &&relationship,
    3528             :     std::string &failureReason)
    3529             : {
    3530           2 :     const std::string osName(relationship->GetName());
    3531           1 :     const auto iter = m_poPrivate->m_oMapRelationships.find(osName);
    3532           1 :     if (iter != m_poPrivate->m_oMapRelationships.end())
    3533             :     {
    3534           0 :         failureReason = "A relationship of identical name already exists";
    3535           0 :         return false;
    3536             :     }
    3537           1 :     m_poPrivate->m_oMapRelationships[osName] = std::move(relationship);
    3538           1 :     return true;
    3539             : }
    3540             : 
    3541             : /************************************************************************/
    3542             : /*                         DeleteRelationship()                         */
    3543             : /************************************************************************/
    3544             : 
    3545           2 : bool MEMDataset::DeleteRelationship(const std::string &name,
    3546             :                                     std::string &failureReason)
    3547             : {
    3548           2 :     const auto iter = m_poPrivate->m_oMapRelationships.find(name);
    3549           2 :     if (iter == m_poPrivate->m_oMapRelationships.end())
    3550             :     {
    3551           1 :         failureReason = "No matching relationship found";
    3552           1 :         return false;
    3553             :     }
    3554           1 :     m_poPrivate->m_oMapRelationships.erase(iter);
    3555           1 :     return true;
    3556             : }
    3557             : 
    3558             : /************************************************************************/
    3559             : /*                         UpdateRelationship()                         */
    3560             : /************************************************************************/
    3561             : 
    3562           2 : bool MEMDataset::UpdateRelationship(
    3563             :     std::unique_ptr<GDALRelationship> &&relationship,
    3564             :     std::string &failureReason)
    3565             : {
    3566           4 :     const std::string osName(relationship->GetName());
    3567           2 :     const auto iter = m_poPrivate->m_oMapRelationships.find(osName);
    3568           2 :     if (iter == m_poPrivate->m_oMapRelationships.end())
    3569             :     {
    3570           1 :         failureReason = "No matching relationship found";
    3571           1 :         return false;
    3572             :     }
    3573           1 :     iter->second = std::move(relationship);
    3574           1 :     return true;
    3575             : }
    3576             : 
    3577             : /************************************************************************/
    3578             : /*                             ExecuteSQL()                             */
    3579             : /************************************************************************/
    3580             : 
    3581         930 : OGRLayer *MEMDataset::ExecuteSQL(const char *pszStatement,
    3582             :                                  OGRGeometry *poSpatialFilter,
    3583             :                                  const char *pszDialect)
    3584             : {
    3585         930 :     if (EQUAL(pszStatement, "PRAGMA read_only=1"))  // as used by VDV driver
    3586             :     {
    3587          35 :         for (auto &poLayer : m_apoLayers)
    3588          28 :             poLayer->SetUpdatable(false);
    3589           7 :         return nullptr;
    3590             :     }
    3591         923 :     return GDALDataset::ExecuteSQL(pszStatement, poSpatialFilter, pszDialect);
    3592             : }
    3593             : 
    3594             : /************************************************************************/
    3595             : /*                          GDALRegister_MEM()                          */
    3596             : /************************************************************************/
    3597             : 
    3598        2135 : void GDALRegister_MEM()
    3599             : {
    3600        2135 :     auto poDM = GetGDALDriverManager();
    3601        2135 :     if (poDM->GetDriverByName("MEM") != nullptr)
    3602         263 :         return;
    3603             : 
    3604        1872 :     GDALDriver *poDriver = new GDALDriver();
    3605             : 
    3606        1872 :     poDriver->SetDescription("MEM");
    3607        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    3608        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
    3609        1872 :     poDriver->SetMetadataItem(
    3610             :         GDAL_DMD_LONGNAME,
    3611        1872 :         "In Memory raster, vector and multidimensional raster");
    3612        1872 :     poDriver->SetMetadataItem(
    3613             :         GDAL_DMD_CREATIONDATATYPES,
    3614             :         "Byte Int8 Int16 UInt16 Int32 UInt32 Int64 UInt64 Float32 Float64 "
    3615        1872 :         "CInt16 CInt32 CFloat32 CFloat64");
    3616        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES");
    3617             : 
    3618        1872 :     poDriver->SetMetadataItem(
    3619             :         GDAL_DMD_CREATIONOPTIONLIST,
    3620             :         "<CreationOptionList>"
    3621             :         "   <Option name='INTERLEAVE' type='string-select' default='BAND'>"
    3622             :         "       <Value>BAND</Value>"
    3623             :         "       <Value>PIXEL</Value>"
    3624             :         "   </Option>"
    3625             :         "  <Option name='NBITS' type='int' description='Bit depth per band'/>"
    3626        1872 :         "</CreationOptionList>");
    3627             : 
    3628        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
    3629        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
    3630        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES");
    3631        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
    3632        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
    3633        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
    3634        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
    3635        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
    3636        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
    3637        1872 :     poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
    3638             : 
    3639        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_RELATIONSHIPS, "YES");
    3640        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_RELATIONSHIP, "YES");
    3641        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_DELETE_RELATIONSHIP, "YES");
    3642        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_UPDATE_RELATIONSHIP, "YES");
    3643        1872 :     poDriver->SetMetadataItem(
    3644             :         GDAL_DMD_RELATIONSHIP_FLAGS,
    3645             :         "OneToOne OneToMany ManyToOne ManyToMany Composite Association "
    3646        1872 :         "Aggregation ForwardPathLabel MultipleFieldKeys BackwardPathLabel");
    3647             : 
    3648        1872 :     poDriver->SetMetadataItem(
    3649             :         GDAL_DMD_CREATIONFIELDDATATYPES,
    3650             :         "Integer Integer64 Real String Date DateTime Time IntegerList "
    3651        1872 :         "Integer64List RealList StringList Binary");
    3652        1872 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES,
    3653        1872 :                               "Boolean Int16 Float32 JSON UUID");
    3654        1872 :     poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
    3655             :                               "WidthPrecision Nullable Default Unique "
    3656        1872 :                               "Comment AlternativeName Domain");
    3657        1872 :     poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
    3658             :                               "Name Type WidthPrecision Nullable Default "
    3659        1872 :                               "Unique Domain AlternativeName Comment");
    3660             : 
    3661        1872 :     poDriver->SetMetadataItem(
    3662             :         GDAL_DS_LAYER_CREATIONOPTIONLIST,
    3663             :         "<LayerCreationOptionList>"
    3664             :         "  <Option name='ADVERTIZE_UTF8' type='boolean' description='Whether "
    3665             :         "the layer will contain UTF-8 strings' default='NO'/>"
    3666             :         "  <Option name='FID' type='string' description="
    3667             :         "'Name of the FID column to create' default='' />"
    3668        1872 :         "</LayerCreationOptionList>");
    3669             : 
    3670        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES");
    3671        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES");
    3672             : 
    3673        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_FIELD_DOMAINS, "YES");
    3674        1872 :     poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DOMAIN_TYPES,
    3675        1872 :                               "Coded Range Glob");
    3676             : 
    3677        1872 :     poDriver->SetMetadataItem(GDAL_DMD_ALTER_GEOM_FIELD_DEFN_FLAGS,
    3678        1872 :                               "Name Type Nullable SRS CoordinateEpoch");
    3679        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_UPSERT, "YES");
    3680             : 
    3681             :     // Define GDAL_NO_OPEN_FOR_MEM_DRIVER macro to undefine Open() method for
    3682             :     // MEM driver.  Otherwise, bad user input can trigger easily a GDAL crash
    3683             :     // as random pointers can be passed as a string.  All code in GDAL tree
    3684             :     // using the MEM driver use the Create() method only, so Open() is not
    3685             :     // needed, except for esoteric uses.
    3686             : #ifndef GDAL_NO_OPEN_FOR_MEM_DRIVER
    3687        1872 :     poDriver->pfnOpen = MEMDataset::Open;
    3688        1872 :     poDriver->pfnIdentify = MEMDatasetIdentify;
    3689             : #endif
    3690        1872 :     poDriver->pfnCreate = MEMDataset::CreateBase;
    3691        1872 :     poDriver->pfnCreateMultiDimensional = MEMDataset::CreateMultiDimensional;
    3692        1872 :     poDriver->pfnDelete = MEMDatasetDelete;
    3693             : 
    3694        1872 :     poDM->RegisterDriver(poDriver);
    3695             : }

Generated by: LCOV version 1.14