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

Generated by: LCOV version 1.14