LCOV - code coverage report
Current view: top level - frmts/mem - memdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1453 1564 92.9 %
Date: 2025-05-31 00:00:17 Functions: 113 120 94.2 %

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

Generated by: LCOV version 1.14