LCOV - code coverage report
Current view: top level - frmts/mem - memdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1489 1599 93.1 %
Date: 2025-10-01 17:07:58 Functions: 115 122 94.3 %

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

Generated by: LCOV version 1.14