LCOV - code coverage report
Current view: top level - frmts/mem - memdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1480 1594 92.8 %
Date: 2026-02-12 23:49:34 Functions: 114 122 93.4 %

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

Generated by: LCOV version 1.14