LCOV - code coverage report
Current view: top level - frmts/mem - memdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1449 1559 92.9 %
Date: 2025-07-11 10:11:13 Functions: 113 120 94.2 %

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

Generated by: LCOV version 1.14