LCOV - code coverage report
Current view: top level - frmts/mem - memdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1299 1405 92.5 %
Date: 2024-04-29 12:21:24 Functions: 102 109 93.6 %

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

Generated by: LCOV version 1.14