• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.94
/frmts/mem/memdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  Memory Array Translator
4
 * Purpose:  Complete implementation.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2000, Frank Warmerdam
9
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "cpl_port.h"
15
#include "memdataset.h"
16
#include "memmultidim.h"
17

18
#include <algorithm>
19
#include <climits>
20
#include <cstdlib>
21
#include <cstring>
22
#include <limits>
23
#include <vector>
24

25
#include "cpl_config.h"
26
#include "cpl_conv.h"
27
#include "cpl_error.h"
28
#include "cpl_minixml.h"
29
#include "cpl_progress.h"
30
#include "cpl_string.h"
31
#include "cpl_vsi.h"
32
#include "gdal.h"
33
#include "gdal_frmts.h"
34

35
struct MEMDataset::Private
36
{
37
    std::shared_ptr<GDALGroup> m_poRootGroup{};
38
};
39

40
/************************************************************************/
41
/*                        MEMCreateRasterBand()                         */
42
/************************************************************************/
43

44
GDALRasterBandH MEMCreateRasterBand(GDALDataset *poDS, int nBand,
×
45
                                    GByte *pabyData, GDALDataType eType,
46
                                    int nPixelOffset, int nLineOffset,
47
                                    int bAssumeOwnership)
48

49
{
50
    return GDALRasterBand::ToHandle(
×
51
        new MEMRasterBand(poDS, nBand, pabyData, eType, nPixelOffset,
52
                          nLineOffset, bAssumeOwnership));
×
53
}
54

55
/************************************************************************/
56
/*                       MEMCreateRasterBandEx()                        */
57
/************************************************************************/
58

59
GDALRasterBandH MEMCreateRasterBandEx(GDALDataset *poDS, int nBand,
15,928✔
60
                                      GByte *pabyData, GDALDataType eType,
61
                                      GSpacing nPixelOffset,
62
                                      GSpacing nLineOffset,
63
                                      int bAssumeOwnership)
64

65
{
66
    return GDALRasterBand::ToHandle(
15,928✔
67
        new MEMRasterBand(poDS, nBand, pabyData, eType, nPixelOffset,
68
                          nLineOffset, bAssumeOwnership));
31,856✔
69
}
70

71
/************************************************************************/
72
/*                           MEMRasterBand()                            */
73
/************************************************************************/
74

75
MEMRasterBand::MEMRasterBand(GByte *pabyDataIn, GDALDataType eTypeIn,
63✔
76
                             int nXSizeIn, int nYSizeIn, bool bOwnDataIn)
63✔
77
    : GDALPamRasterBand(FALSE), pabyData(pabyDataIn),
78
      nPixelOffset(GDALGetDataTypeSizeBytes(eTypeIn)), nLineOffset(0),
126✔
79
      bOwnData(bOwnDataIn)
63✔
80
{
81
    eAccess = GA_Update;
63✔
82
    eDataType = eTypeIn;
63✔
83
    nRasterXSize = nXSizeIn;
63✔
84
    nRasterYSize = nYSizeIn;
63✔
85
    nBlockXSize = nXSizeIn;
63✔
86
    nBlockYSize = 1;
63✔
87
    nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize);
63✔
88

89
    PamInitializeNoParent();
63✔
90
}
63✔
91

92
/************************************************************************/
93
/*                           MEMRasterBand()                            */
94
/************************************************************************/
95

96
MEMRasterBand::MEMRasterBand(GDALDataset *poDSIn, int nBandIn,
111,665✔
97
                             GByte *pabyDataIn, GDALDataType eTypeIn,
98
                             GSpacing nPixelOffsetIn, GSpacing nLineOffsetIn,
99
                             int bAssumeOwnership, const char *pszPixelType)
111,665✔
100
    : GDALPamRasterBand(FALSE), pabyData(pabyDataIn),
101
      nPixelOffset(nPixelOffsetIn), nLineOffset(nLineOffsetIn),
102
      bOwnData(bAssumeOwnership)
111,665✔
103
{
104
    poDS = poDSIn;
111,643✔
105
    nBand = nBandIn;
111,643✔
106

107
    eAccess = poDS->GetAccess();
111,643✔
108

109
    eDataType = eTypeIn;
111,644✔
110

111
    nBlockXSize = poDS->GetRasterXSize();
111,644✔
112
    nBlockYSize = 1;
111,639✔
113

114
    if (nPixelOffsetIn == 0)
111,639✔
115
        nPixelOffset = GDALGetDataTypeSizeBytes(eTypeIn);
105,521✔
116

117
    if (nLineOffsetIn == 0)
111,639✔
118
        nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize);
105,640✔
119

120
    if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
111,639✔
121
        SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE");
×
122

123
    PamInitializeNoParent();
111,639✔
124
}
111,650✔
125

126
/************************************************************************/
127
/*                           ~MEMRasterBand()                           */
128
/************************************************************************/
129

130
MEMRasterBand::~MEMRasterBand()
223,472✔
131

132
{
133
    if (bOwnData)
111,736✔
134
    {
135
        VSIFree(pabyData);
8,951✔
136
    }
137
}
223,472✔
138

139
/************************************************************************/
140
/*                             IReadBlock()                             */
141
/************************************************************************/
142

143
CPLErr MEMRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
20,749✔
144
                                 void *pImage)
145
{
146
    CPLAssert(nBlockXOff == 0);
20,749✔
147

148
    const int nWordSize = GDALGetDataTypeSizeBytes(eDataType);
20,749✔
149

150
    if (nPixelOffset == nWordSize)
20,750✔
151
    {
152
        memcpy(pImage, pabyData + nLineOffset * static_cast<size_t>(nBlockYOff),
20,650✔
153
               static_cast<size_t>(nPixelOffset) * nBlockXSize);
20,650✔
154
    }
155
    else
156
    {
157
        GByte *const pabyCur =
100✔
158
            pabyData + nLineOffset * static_cast<size_t>(nBlockYOff);
100✔
159

160
        for (int iPixel = 0; iPixel < nBlockXSize; iPixel++)
10,924✔
161
        {
162
            memcpy(static_cast<GByte *>(pImage) + iPixel * nWordSize,
10,824✔
163
                   pabyCur + iPixel * nPixelOffset, nWordSize);
10,824✔
164
        }
165
    }
166

167
    return CE_None;
20,750✔
168
}
169

170
/************************************************************************/
171
/*                            IWriteBlock()                             */
172
/************************************************************************/
173

174
CPLErr MEMRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
80,083✔
175
                                  void *pImage)
176
{
177
    CPLAssert(nBlockXOff == 0);
80,083✔
178
    const int nWordSize = GDALGetDataTypeSizeBytes(eDataType);
80,083✔
179

180
    if (nPixelOffset == nWordSize)
80,083✔
181
    {
182
        memcpy(pabyData + nLineOffset * static_cast<size_t>(nBlockYOff), pImage,
79,673✔
183
               static_cast<size_t>(nPixelOffset) * nBlockXSize);
79,673✔
184
    }
185
    else
186
    {
187
        GByte *pabyCur =
410✔
188
            pabyData + nLineOffset * static_cast<size_t>(nBlockYOff);
410✔
189

190
        for (int iPixel = 0; iPixel < nBlockXSize; iPixel++)
25,910✔
191
        {
192
            memcpy(pabyCur + iPixel * nPixelOffset,
25,500✔
193
                   static_cast<GByte *>(pImage) + iPixel * nWordSize,
25,500✔
194
                   nWordSize);
195
        }
196
    }
197

198
    return CE_None;
80,083✔
199
}
200

201
/************************************************************************/
202
/*                             IRasterIO()                              */
203
/************************************************************************/
204

205
CPLErr MEMRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
1,665,760✔
206
                                int nXSize, int nYSize, void *pData,
207
                                int nBufXSize, int nBufYSize,
208
                                GDALDataType eBufType, GSpacing nPixelSpaceBuf,
209
                                GSpacing nLineSpaceBuf,
210
                                GDALRasterIOExtraArg *psExtraArg)
211
{
212
    if (nXSize != nBufXSize || nYSize != nBufYSize)
1,665,760✔
213
    {
214
        return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
18,098✔
215
                                         pData, nBufXSize, nBufYSize, eBufType,
216
                                         static_cast<int>(nPixelSpaceBuf),
217
                                         nLineSpaceBuf, psExtraArg);
473✔
218
    }
219

220
    // In case block based I/O has been done before.
221
    FlushCache(false);
1,647,660✔
222

223
    if (eRWFlag == GF_Read)
1,653,760✔
224
    {
225
        for (int iLine = 0; iLine < nYSize; iLine++)
9,645,980✔
226
        {
227
            GDALCopyWords(pabyData +
8,053,870✔
228
                              nLineOffset *
8,053,870✔
229
                                  static_cast<GPtrDiff_t>(iLine + nYOff) +
8,053,870✔
230
                              nXOff * nPixelOffset,
8,053,870✔
231
                          eDataType, static_cast<int>(nPixelOffset),
8,053,870✔
232
                          static_cast<GByte *>(pData) +
233
                              nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine),
8,053,870✔
234
                          eBufType, static_cast<int>(nPixelSpaceBuf), nXSize);
235
        }
236
    }
237
    else
238
    {
239
        for (int iLine = 0; iLine < nYSize; iLine++)
1,736,360✔
240
        {
241
            GDALCopyWords(static_cast<GByte *>(pData) +
1,632,590✔
242
                              nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine),
1,632,590✔
243
                          eBufType, static_cast<int>(nPixelSpaceBuf),
244
                          pabyData +
1,632,590✔
245
                              nLineOffset *
1,632,590✔
246
                                  static_cast<GPtrDiff_t>(iLine + nYOff) +
1,632,590✔
247
                              nXOff * nPixelOffset,
1,632,590✔
248
                          eDataType, static_cast<int>(nPixelOffset), nXSize);
1,632,590✔
249
        }
250
    }
251
    return CE_None;
1,695,880✔
252
}
253

254
/************************************************************************/
255
/*                             IRasterIO()                              */
256
/************************************************************************/
257

258
CPLErr MEMDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
340,743✔
259
                             int nXSize, int nYSize, void *pData, int nBufXSize,
260
                             int nBufYSize, GDALDataType eBufType,
261
                             int nBandCount, BANDMAP_TYPE panBandMap,
262
                             GSpacing nPixelSpaceBuf, GSpacing nLineSpaceBuf,
263
                             GSpacing nBandSpaceBuf,
264
                             GDALRasterIOExtraArg *psExtraArg)
265
{
266
    const int eBufTypeSize = GDALGetDataTypeSizeBytes(eBufType);
340,743✔
267

268
    // Detect if we have a pixel-interleaved buffer
269
    if (nXSize == nBufXSize && nYSize == nBufYSize && nBandCount == nBands &&
340,722✔
270
        nBands > 1 && nBandSpaceBuf == eBufTypeSize &&
336,262✔
271
        nPixelSpaceBuf == nBandSpaceBuf * nBands)
194,218✔
272
    {
273
        const auto IsPixelInterleaveDataset = [this, nBandCount, panBandMap]()
971,742✔
274
        {
275
            GDALDataType eDT = GDT_Unknown;
194,093✔
276
            GByte *pabyData = nullptr;
194,093✔
277
            GSpacing nPixelOffset = 0;
194,093✔
278
            GSpacing nLineOffset = 0;
194,093✔
279
            int eDTSize = 0;
194,093✔
280
            for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
194,529✔
281
            {
282
                if (panBandMap[iBandIndex] != iBandIndex + 1)
194,518✔
283
                    return false;
×
284

285
                MEMRasterBand *poBand = cpl::down_cast<MEMRasterBand *>(
194,518✔
286
                    GetRasterBand(iBandIndex + 1));
287
                if (iBandIndex == 0)
194,511✔
288
                {
289
                    eDT = poBand->GetRasterDataType();
194,089✔
290
                    pabyData = poBand->pabyData;
194,079✔
291
                    nPixelOffset = poBand->nPixelOffset;
194,079✔
292
                    nLineOffset = poBand->nLineOffset;
194,079✔
293
                    eDTSize = GDALGetDataTypeSizeBytes(eDT);
194,079✔
294
                    if (nPixelOffset != static_cast<GSpacing>(nBands) * eDTSize)
194,084✔
295
                        return false;
193,670✔
296
                }
297
                else if (poBand->GetRasterDataType() != eDT ||
422✔
298
                         nPixelOffset != poBand->nPixelOffset ||
422✔
299
                         nLineOffset != poBand->nLineOffset ||
1,266✔
300
                         poBand->pabyData != pabyData + iBandIndex * eDTSize)
422✔
301
                {
302
                    return false;
400✔
303
                }
304
            }
305
            return true;
11✔
306
        };
194,095✔
307

308
        const auto IsBandSeparatedDataset = [this, nBandCount, panBandMap]()
14,311✔
309
        {
310
            GDALDataType eDT = GDT_Unknown;
1,124✔
311
            GSpacing nPixelOffset = 0;
1,124✔
312
            GSpacing nLineOffset = 0;
1,124✔
313
            int eDTSize = 0;
1,124✔
314
            for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
5,145✔
315
            {
316
                if (panBandMap[iBandIndex] != iBandIndex + 1)
4,021✔
317
                    return false;
×
318

319
                MEMRasterBand *poBand = cpl::down_cast<MEMRasterBand *>(
4,021✔
320
                    GetRasterBand(iBandIndex + 1));
321
                if (iBandIndex == 0)
4,021✔
322
                {
323
                    eDT = poBand->GetRasterDataType();
1,124✔
324
                    nPixelOffset = poBand->nPixelOffset;
1,124✔
325
                    nLineOffset = poBand->nLineOffset;
1,124✔
326
                    eDTSize = GDALGetDataTypeSizeBytes(eDT);
1,124✔
327
                    if (nPixelOffset != eDTSize)
1,124✔
328
                        return false;
×
329
                }
330
                else if (poBand->GetRasterDataType() != eDT ||
2,897✔
331
                         nPixelOffset != poBand->nPixelOffset ||
5,794✔
332
                         nLineOffset != poBand->nLineOffset)
2,897✔
333
                {
334
                    return false;
×
335
                }
336
            }
337
            return true;
1,124✔
338
        };
194,095✔
339

340
        if (IsPixelInterleaveDataset())
194,095✔
341
        {
342
            FlushCache(false);
11✔
343
            const auto poFirstBand =
344
                cpl::down_cast<MEMRasterBand *>(papoBands[0]);
11✔
345
            const GDALDataType eDT = poFirstBand->GetRasterDataType();
11✔
346
            GByte *pabyData = poFirstBand->pabyData;
11✔
347
            const GSpacing nPixelOffset = poFirstBand->nPixelOffset;
11✔
348
            const GSpacing nLineOffset = poFirstBand->nLineOffset;
11✔
349
            const int eDTSize = GDALGetDataTypeSizeBytes(eDT);
11✔
350
            if (eRWFlag == GF_Read)
11✔
351
            {
352
                for (int iLine = 0; iLine < nYSize; iLine++)
42✔
353
                {
354
                    GDALCopyWords(
35✔
355
                        pabyData +
356
                            nLineOffset * static_cast<size_t>(iLine + nYOff) +
35✔
357
                            nXOff * nPixelOffset,
35✔
358
                        eDT, eDTSize,
359
                        static_cast<GByte *>(pData) +
360
                            nLineSpaceBuf * static_cast<size_t>(iLine),
35✔
361
                        eBufType, eBufTypeSize, nXSize * nBands);
35✔
362
                }
363
            }
364
            else
365
            {
366
                for (int iLine = 0; iLine < nYSize; iLine++)
24✔
367
                {
368
                    GDALCopyWords(
20✔
369
                        static_cast<GByte *>(pData) +
20✔
370
                            nLineSpaceBuf * static_cast<size_t>(iLine),
20✔
371
                        eBufType, eBufTypeSize,
372
                        pabyData +
373
                            nLineOffset * static_cast<size_t>(iLine + nYOff) +
20✔
374
                            nXOff * nPixelOffset,
20✔
375
                        eDT, eDTSize, nXSize * nBands);
20✔
376
                }
377
            }
378
            return CE_None;
1,135✔
379
        }
380
        else if (eRWFlag == GF_Write && nBandCount <= 4 &&
195,189✔
381
                 IsBandSeparatedDataset())
1,124✔
382
        {
383
            // TODO: once we have a GDALInterleave() function, implement the
384
            // GF_Read case
385
            FlushCache(false);
1,124✔
386
            const auto poFirstBand =
387
                cpl::down_cast<MEMRasterBand *>(papoBands[0]);
1,124✔
388
            const GDALDataType eDT = poFirstBand->GetRasterDataType();
1,124✔
389
            void *ppDestBuffer[4] = {nullptr, nullptr, nullptr, nullptr};
1,124✔
390
            if (nXOff == 0 && nXSize == nRasterXSize &&
1,124✔
391
                poFirstBand->nLineOffset ==
1,116✔
392
                    poFirstBand->nPixelOffset * nXSize &&
1,116✔
393
                nLineSpaceBuf == nPixelSpaceBuf * nXSize)
1,116✔
394
            {
395
                // Optimization of the general case in the below else() clause:
396
                // writing whole strips from a fully packed buffer
397
                for (int i = 0; i < nBandCount; ++i)
5,113✔
398
                {
399
                    const auto poBand =
400
                        cpl::down_cast<MEMRasterBand *>(papoBands[i]);
3,997✔
401
                    ppDestBuffer[i] =
3,997✔
402
                        poBand->pabyData + poBand->nLineOffset * nYOff;
3,997✔
403
                }
404
                GDALDeinterleave(pData, eBufType, nBandCount, ppDestBuffer, eDT,
1,116✔
405
                                 static_cast<size_t>(nXSize) * nYSize);
1,116✔
406
            }
407
            else
408
            {
409
                for (int iLine = 0; iLine < nYSize; iLine++)
103✔
410
                {
411
                    for (int i = 0; i < nBandCount; ++i)
380✔
412
                    {
413
                        const auto poBand =
414
                            cpl::down_cast<MEMRasterBand *>(papoBands[i]);
285✔
415
                        ppDestBuffer[i] = poBand->pabyData +
285✔
416
                                          poBand->nPixelOffset * nXOff +
285✔
417
                                          poBand->nLineOffset * (iLine + nYOff);
285✔
418
                    }
419
                    GDALDeinterleave(
95✔
420
                        static_cast<GByte *>(pData) +
95✔
421
                            nLineSpaceBuf * static_cast<size_t>(iLine),
95✔
422
                        eBufType, nBandCount, ppDestBuffer, eDT, nXSize);
423
                }
424
            }
425
            return CE_None;
1,124✔
426
        }
427
    }
428

429
    if (nBufXSize != nXSize || nBufYSize != nYSize)
339,568✔
430
        return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
285✔
431
                                      pData, nBufXSize, nBufYSize, eBufType,
432
                                      nBandCount, panBandMap, nPixelSpaceBuf,
433
                                      nLineSpaceBuf, nBandSpaceBuf, psExtraArg);
312✔
434

435
    return GDALDataset::BandBasedRasterIO(
339,283✔
436
        eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
437
        eBufType, nBandCount, panBandMap, nPixelSpaceBuf, nLineSpaceBuf,
438
        nBandSpaceBuf, psExtraArg);
339,306✔
439
}
440

441
/************************************************************************/
442
/*                          GetOverviewCount()                          */
443
/************************************************************************/
444

445
int MEMRasterBand::GetOverviewCount()
4,981✔
446
{
447
    MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
4,981✔
448
    if (poMemDS == nullptr)
4,981✔
449
        return 0;
6✔
450
    return static_cast<int>(poMemDS->m_apoOverviewDS.size());
4,975✔
451
}
452

453
/************************************************************************/
454
/*                            GetOverview()                             */
455
/************************************************************************/
456

457
GDALRasterBand *MEMRasterBand::GetOverview(int i)
56,435✔
458

459
{
460
    MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
56,435✔
461
    if (poMemDS == nullptr)
56,435✔
462
        return nullptr;
×
463
    if (i < 0 || i >= static_cast<int>(poMemDS->m_apoOverviewDS.size()))
56,435✔
464
        return nullptr;
17✔
465
    return poMemDS->m_apoOverviewDS[i]->GetRasterBand(nBand);
58,781✔
466
}
467

468
/************************************************************************/
469
/*                         CreateMaskBand()                             */
470
/************************************************************************/
471

472
CPLErr MEMRasterBand::CreateMaskBand(int nFlagsIn)
62✔
473
{
474
    InvalidateMaskBand();
62✔
475

476
    MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
62✔
477
    if ((nFlagsIn & GMF_PER_DATASET) != 0 && nBand != 1 && poMemDS != nullptr)
62✔
478
    {
479
        MEMRasterBand *poFirstBand =
480
            dynamic_cast<MEMRasterBand *>(poMemDS->GetRasterBand(1));
1✔
481
        if (poFirstBand != nullptr)
1✔
482
            return poFirstBand->CreateMaskBand(nFlagsIn);
1✔
483
    }
484

485
    GByte *pabyMaskData =
486
        static_cast<GByte *>(VSI_CALLOC_VERBOSE(nRasterXSize, nRasterYSize));
61✔
487
    if (pabyMaskData == nullptr)
61✔
488
        return CE_Failure;
×
489

490
    nMaskFlags = nFlagsIn;
61✔
491
    auto poMemMaskBand = std::unique_ptr<MEMRasterBand>(
492
        new MEMRasterBand(pabyMaskData, GDT_Byte, nRasterXSize, nRasterYSize,
493
                          /* bOwnData= */ true));
61✔
494
    poMemMaskBand->m_bIsMask = true;
61✔
495
    poMask.reset(std::move(poMemMaskBand));
61✔
496
    if ((nFlagsIn & GMF_PER_DATASET) != 0 && nBand == 1 && poMemDS != nullptr)
61✔
497
    {
498
        for (int i = 2; i <= poMemDS->GetRasterCount(); ++i)
69✔
499
        {
500
            MEMRasterBand *poOtherBand =
501
                cpl::down_cast<MEMRasterBand *>(poMemDS->GetRasterBand(i));
13✔
502
            poOtherBand->InvalidateMaskBand();
13✔
503
            poOtherBand->nMaskFlags = nFlagsIn;
13✔
504
            poOtherBand->poMask.resetNotOwned(poMask.get());
13✔
505
        }
506
    }
507
    return CE_None;
61✔
508
}
509

510
/************************************************************************/
511
/*                            IsMaskBand()                              */
512
/************************************************************************/
513

514
bool MEMRasterBand::IsMaskBand() const
364✔
515
{
516
    return m_bIsMask || GDALPamRasterBand::IsMaskBand();
364✔
517
}
518

519
/************************************************************************/
520
/* ==================================================================== */
521
/*      MEMDataset                                                     */
522
/* ==================================================================== */
523
/************************************************************************/
524

525
/************************************************************************/
526
/*                            MEMDataset()                             */
527
/************************************************************************/
528

529
MEMDataset::MEMDataset()
18,829✔
530
    : GDALDataset(FALSE), bGeoTransformSet(FALSE), m_poPrivate(new Private())
18,829✔
531
{
532
    m_gt[5] = -1;
18,819✔
533
    DisableReadWriteMutex();
18,816✔
534
}
18,825✔
535

536
/************************************************************************/
537
/*                            ~MEMDataset()                            */
538
/************************************************************************/
539

540
MEMDataset::~MEMDataset()
37,584✔
541

542
{
543
    const bool bSuppressOnCloseBackup = bSuppressOnClose;
18,792✔
544
    bSuppressOnClose = true;
18,792✔
545
    FlushCache(true);
18,792✔
546
    bSuppressOnClose = bSuppressOnCloseBackup;
18,792✔
547
}
37,584✔
548

549
#if 0
550
/************************************************************************/
551
/*                          EnterReadWrite()                            */
552
/************************************************************************/
553

554
int MEMDataset::EnterReadWrite(CPL_UNUSED GDALRWFlag eRWFlag)
555
{
556
    return TRUE;
557
}
558

559
/************************************************************************/
560
/*                         LeaveReadWrite()                             */
561
/************************************************************************/
562

563
void MEMDataset::LeaveReadWrite()
564
{
565
}
566
#endif  // if 0
567

568
/************************************************************************/
569
/*                          GetSpatialRef()                             */
570
/************************************************************************/
571

572
const OGRSpatialReference *MEMDataset::GetSpatialRef() const
11,420✔
573

574
{
575
    return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
11,420✔
576
}
577

578
/************************************************************************/
579
/*                           SetSpatialRef()                            */
580
/************************************************************************/
581

582
CPLErr MEMDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
1,482✔
583

584
{
585
    m_oSRS.Clear();
1,482✔
586
    if (poSRS)
1,482✔
587
        m_oSRS = *poSRS;
1,426✔
588

589
    return CE_None;
1,482✔
590
}
591

592
/************************************************************************/
593
/*                          GetGeoTransform()                           */
594
/************************************************************************/
595

596
CPLErr MEMDataset::GetGeoTransform(GDALGeoTransform &gt) const
11,657✔
597

598
{
599
    gt = m_gt;
11,657✔
600
    if (bGeoTransformSet)
11,657✔
601
        return CE_None;
5,880✔
602

603
    return CE_Failure;
5,777✔
604
}
605

606
/************************************************************************/
607
/*                          SetGeoTransform()                           */
608
/************************************************************************/
609

610
CPLErr MEMDataset::SetGeoTransform(const GDALGeoTransform &gt)
2,341✔
611

612
{
613
    m_gt = gt;
2,341✔
614
    bGeoTransformSet = TRUE;
2,341✔
615

616
    return CE_None;
2,341✔
617
}
618

619
/************************************************************************/
620
/*                          GetInternalHandle()                         */
621
/************************************************************************/
622

623
void *MEMDataset::GetInternalHandle(const char *pszRequest)
562✔
624

625
{
626
    // check for MEMORYnnn string in pszRequest (nnnn can be up to 10
627
    // digits, or even omitted)
628
    if (STARTS_WITH_CI(pszRequest, "MEMORY"))
562✔
629
    {
630
        if (int BandNumber = static_cast<int>(CPLScanLong(&pszRequest[6], 10)))
477✔
631
        {
632
            MEMRasterBand *RequestedRasterBand =
633
                cpl::down_cast<MEMRasterBand *>(GetRasterBand(BandNumber));
477✔
634

635
            // we're within a MEMDataset so the only thing a RasterBand
636
            // could be is a MEMRasterBand
637

638
            if (RequestedRasterBand != nullptr)
477✔
639
            {
640
                // return the internal band data pointer
641
                return RequestedRasterBand->GetData();
477✔
642
            }
643
        }
644
    }
645

646
    return nullptr;
85✔
647
}
648

649
/************************************************************************/
650
/*                            GetGCPCount()                             */
651
/************************************************************************/
652

653
int MEMDataset::GetGCPCount()
7,196✔
654

655
{
656
    return static_cast<int>(m_aoGCPs.size());
7,196✔
657
}
658

659
/************************************************************************/
660
/*                          GetGCPSpatialRef()                          */
661
/************************************************************************/
662

663
const OGRSpatialReference *MEMDataset::GetGCPSpatialRef() const
233✔
664

665
{
666
    return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
233✔
667
}
668

669
/************************************************************************/
670
/*                              GetGCPs()                               */
671
/************************************************************************/
672

673
const GDAL_GCP *MEMDataset::GetGCPs()
63✔
674

675
{
676
    return gdal::GCP::c_ptr(m_aoGCPs);
63✔
677
}
678

679
/************************************************************************/
680
/*                              SetGCPs()                               */
681
/************************************************************************/
682

683
CPLErr MEMDataset::SetGCPs(int nNewCount, const GDAL_GCP *pasNewGCPList,
10✔
684
                           const OGRSpatialReference *poSRS)
685

686
{
687
    m_oGCPSRS.Clear();
10✔
688
    if (poSRS)
10✔
689
        m_oGCPSRS = *poSRS;
6✔
690

691
    m_aoGCPs = gdal::GCP::fromC(pasNewGCPList, nNewCount);
10✔
692

693
    return CE_None;
10✔
694
}
695

696
/************************************************************************/
697
/*                              AddBand()                               */
698
/*                                                                      */
699
/*      Add a new band to the dataset, allowing creation options to     */
700
/*      specify the existing memory to use, otherwise create new        */
701
/*      memory.                                                         */
702
/************************************************************************/
703

704
CPLErr MEMDataset::AddBand(GDALDataType eType, char **papszOptions)
2,764✔
705

706
{
707
    const int nBandId = GetRasterCount() + 1;
2,764✔
708
    const GSpacing nPixelSize = GDALGetDataTypeSizeBytes(eType);
2,725✔
709
    if (nPixelSize == 0)
2,738✔
710
    {
711
        ReportError(CE_Failure, CPLE_IllegalArg,
1✔
712
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
713
        return CE_Failure;
1✔
714
    }
715

716
    /* -------------------------------------------------------------------- */
717
    /*      Do we need to allocate the memory ourselves?  This is the       */
718
    /*      simple case.                                                    */
719
    /* -------------------------------------------------------------------- */
720
    if (CSLFetchNameValue(papszOptions, "DATAPOINTER") == nullptr)
2,737✔
721
    {
722
        const GSpacing nTmp = nPixelSize * GetRasterXSize();
259✔
723
        GByte *pData =
724
#if SIZEOF_VOIDP == 4
725
            (nTmp > INT_MAX) ? nullptr :
726
#endif
727
                             static_cast<GByte *>(VSI_CALLOC_VERBOSE(
259✔
728
                                 static_cast<size_t>(nTmp), GetRasterYSize()));
729

730
        if (pData == nullptr)
259✔
731
        {
732
            return CE_Failure;
1✔
733
        }
734

735
        SetBand(nBandId,
258✔
736
                new MEMRasterBand(this, nBandId, pData, eType, nPixelSize,
737
                                  nPixelSize * GetRasterXSize(), TRUE));
258✔
738

739
        return CE_None;
258✔
740
    }
741

742
    /* -------------------------------------------------------------------- */
743
    /*      Get layout of memory and other flags.                           */
744
    /* -------------------------------------------------------------------- */
745
    const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER");
2,485✔
746
    GByte *pData = static_cast<GByte *>(CPLScanPointer(
4,993✔
747
        pszDataPointer, static_cast<int>(strlen(pszDataPointer))));
2,500✔
748

749
    const char *pszOption = CSLFetchNameValue(papszOptions, "PIXELOFFSET");
2,493✔
750
    GSpacing nPixelOffset;
751
    if (pszOption == nullptr)
2,487✔
752
        nPixelOffset = nPixelSize;
911✔
753
    else
754
        nPixelOffset = CPLAtoGIntBig(pszOption);
1,576✔
755

756
    pszOption = CSLFetchNameValue(papszOptions, "LINEOFFSET");
2,487✔
757
    GSpacing nLineOffset;
758
    if (pszOption == nullptr)
2,493✔
759
        nLineOffset = GetRasterXSize() * static_cast<size_t>(nPixelOffset);
911✔
760
    else
761
        nLineOffset = CPLAtoGIntBig(pszOption);
1,582✔
762

763
    SetBand(nBandId, new MEMRasterBand(this, nBandId, pData, eType,
2,498✔
764
                                       nPixelOffset, nLineOffset, FALSE));
2,502✔
765

766
    return CE_None;
2,502✔
767
}
768

769
/************************************************************************/
770
/*                           AddMEMBand()                               */
771
/************************************************************************/
772

773
void MEMDataset::AddMEMBand(GDALRasterBandH hMEMBand)
12,848✔
774
{
775
    auto poBand = GDALRasterBand::FromHandle(hMEMBand);
12,848✔
776
    CPLAssert(dynamic_cast<MEMRasterBand *>(poBand) != nullptr);
12,848✔
777
    SetBand(1 + nBands, poBand);
12,848✔
778
}
12,848✔
779

780
/************************************************************************/
781
/*                          IBuildOverviews()                           */
782
/************************************************************************/
783

784
CPLErr MEMDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
168✔
785
                                   const int *panOverviewList, int nListBands,
786
                                   const int *panBandList,
787
                                   GDALProgressFunc pfnProgress,
788
                                   void *pProgressData,
789
                                   CSLConstList papszOptions)
790
{
791
    if (nBands == 0)
168✔
792
    {
793
        CPLError(CE_Failure, CPLE_NotSupported, "Dataset has zero bands.");
1✔
794
        return CE_Failure;
1✔
795
    }
796

797
    if (nListBands != nBands)
167✔
798
    {
799
        CPLError(CE_Failure, CPLE_NotSupported,
×
800
                 "Generation of overviews in MEM only"
801
                 "supported when operating on all bands.");
802
        return CE_Failure;
×
803
    }
804

805
    if (nOverviews == 0)
167✔
806
    {
807
        // Cleanup existing overviews
808
        m_apoOverviewDS.clear();
2✔
809
        return CE_None;
2✔
810
    }
811

812
    /* -------------------------------------------------------------------- */
813
    /*      Force cascading. Help to get accurate results when masks are    */
814
    /*      involved.                                                       */
815
    /* -------------------------------------------------------------------- */
816
    if (nOverviews > 1 &&
165✔
817
        (STARTS_WITH_CI(pszResampling, "AVER") ||
22✔
818
         STARTS_WITH_CI(pszResampling, "GAUSS") ||
21✔
819
         EQUAL(pszResampling, "CUBIC") || EQUAL(pszResampling, "CUBICSPLINE") ||
21✔
820
         EQUAL(pszResampling, "LANCZOS") || EQUAL(pszResampling, "BILINEAR")))
21✔
821
    {
822
        double dfTotalPixels = 0;
6✔
823
        for (int i = 0; i < nOverviews; i++)
18✔
824
        {
825
            dfTotalPixels += static_cast<double>(nRasterXSize) * nRasterYSize /
12✔
826
                             (panOverviewList[i] * panOverviewList[i]);
12✔
827
        }
828

829
        double dfAccPixels = 0;
6✔
830
        for (int i = 0; i < nOverviews; i++)
18✔
831
        {
832
            double dfPixels = static_cast<double>(nRasterXSize) * nRasterYSize /
12✔
833
                              (panOverviewList[i] * panOverviewList[i]);
12✔
834
            void *pScaledProgress = GDALCreateScaledProgress(
24✔
835
                dfAccPixels / dfTotalPixels,
836
                (dfAccPixels + dfPixels) / dfTotalPixels, pfnProgress,
12✔
837
                pProgressData);
838
            CPLErr eErr = IBuildOverviews(
24✔
839
                pszResampling, 1, &panOverviewList[i], nListBands, panBandList,
12✔
840
                GDALScaledProgress, pScaledProgress, papszOptions);
12✔
841
            GDALDestroyScaledProgress(pScaledProgress);
12✔
842
            dfAccPixels += dfPixels;
12✔
843
            if (eErr == CE_Failure)
12✔
844
                return eErr;
×
845
        }
846
        return CE_None;
6✔
847
    }
848

849
    /* -------------------------------------------------------------------- */
850
    /*      Establish which of the overview levels we already have, and     */
851
    /*      which are new.                                                  */
852
    /* -------------------------------------------------------------------- */
853
    GDALRasterBand *poBand = GetRasterBand(1);
159✔
854

855
    for (int i = 0; i < nOverviews; i++)
338✔
856
    {
857
        bool bExisting = false;
179✔
858
        for (int j = 0; j < poBand->GetOverviewCount(); j++)
212✔
859
        {
860
            GDALRasterBand *poOverview = poBand->GetOverview(j);
41✔
861
            if (poOverview == nullptr)
41✔
862
                continue;
×
863

864
            int nOvFactor =
865
                GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
41✔
866
                                    poOverview->GetYSize(), poBand->GetYSize());
867

868
            if (nOvFactor == panOverviewList[i] ||
74✔
869
                nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
33✔
870
                                                poBand->GetXSize(),
871
                                                poBand->GetYSize()))
872
            {
873
                bExisting = true;
8✔
874
                break;
8✔
875
            }
876
        }
877

878
        // Create new overview dataset if needed.
879
        if (!bExisting)
179✔
880
        {
881
            auto poOvrDS = std::make_unique<MEMDataset>();
171✔
882
            poOvrDS->eAccess = GA_Update;
171✔
883
            poOvrDS->nRasterXSize =
171✔
884
                DIV_ROUND_UP(nRasterXSize, panOverviewList[i]);
171✔
885
            poOvrDS->nRasterYSize =
171✔
886
                DIV_ROUND_UP(nRasterYSize, panOverviewList[i]);
171✔
887
            poOvrDS->bGeoTransformSet = bGeoTransformSet;
171✔
888
            poOvrDS->m_gt = m_gt;
171✔
889
            const double dfOvrXRatio =
890
                static_cast<double>(nRasterXSize) / poOvrDS->nRasterXSize;
171✔
891
            const double dfOvrYRatio =
892
                static_cast<double>(nRasterYSize) / poOvrDS->nRasterYSize;
171✔
893
            poOvrDS->m_gt.Rescale(dfOvrXRatio, dfOvrYRatio);
171✔
894
            poOvrDS->m_oSRS = m_oSRS;
171✔
895
            for (int iBand = 0; iBand < nBands; iBand++)
412✔
896
            {
897
                const GDALDataType eDT =
898
                    GetRasterBand(iBand + 1)->GetRasterDataType();
241✔
899
                if (poOvrDS->AddBand(eDT, nullptr) != CE_None)
241✔
900
                {
901
                    return CE_Failure;
×
902
                }
903
            }
904
            m_apoOverviewDS.emplace_back(poOvrDS.release());
171✔
905
        }
906
    }
907

908
    /* -------------------------------------------------------------------- */
909
    /*      Build band list.                                                */
910
    /* -------------------------------------------------------------------- */
911
    GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
912
        CPLCalloc(sizeof(GDALRasterBand *), nBands));
159✔
913
    for (int i = 0; i < nBands; i++)
374✔
914
        pahBands[i] = GetRasterBand(panBandList[i]);
215✔
915

916
    /* -------------------------------------------------------------------- */
917
    /*      Refresh overviews that were listed.                             */
918
    /* -------------------------------------------------------------------- */
919
    GDALRasterBand **papoOverviewBands =
920
        static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
159✔
921
    GDALRasterBand **papoMaskOverviewBands =
922
        static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
159✔
923

924
    CPLErr eErr = CE_None;
159✔
925
    for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
374✔
926
    {
927
        poBand = GetRasterBand(panBandList[iBand]);
215✔
928

929
        int nNewOverviews = 0;
215✔
930
        for (int i = 0; i < nOverviews; i++)
464✔
931
        {
932
            for (int j = 0; j < poBand->GetOverviewCount(); j++)
296✔
933
            {
934
                GDALRasterBand *poOverview = poBand->GetOverview(j);
296✔
935

936
                int bHasNoData = FALSE;
296✔
937
                double noDataValue = poBand->GetNoDataValue(&bHasNoData);
296✔
938

939
                if (bHasNoData)
296✔
940
                    poOverview->SetNoDataValue(noDataValue);
75✔
941

942
                const int nOvFactor = GDALComputeOvFactor(
296✔
943
                    poOverview->GetXSize(), poBand->GetXSize(),
944
                    poOverview->GetYSize(), poBand->GetYSize());
945

946
                if (nOvFactor == panOverviewList[i] ||
343✔
947
                    nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
47✔
948
                                                    poBand->GetXSize(),
949
                                                    poBand->GetYSize()))
950
                {
951
                    papoOverviewBands[nNewOverviews++] = poOverview;
249✔
952
                    break;
249✔
953
                }
954
            }
955
        }
956

957
        // If the band has an explicit mask, we need to create overviews
958
        // for it
959
        MEMRasterBand *poMEMBand = cpl::down_cast<MEMRasterBand *>(poBand);
215✔
960
        const bool bMustGenerateMaskOvr =
961
            ((poMEMBand->poMask != nullptr && poMEMBand->poMask.IsOwned()) ||
270✔
962
             // Or if it is a per-dataset mask, in which case just do it for the
963
             // first band
964
             ((poMEMBand->nMaskFlags & GMF_PER_DATASET) != 0 && iBand == 0)) &&
271✔
965
            dynamic_cast<MEMRasterBand *>(poBand->GetMaskBand()) != nullptr;
54✔
966

967
        if (nNewOverviews > 0 && bMustGenerateMaskOvr)
215✔
968
        {
969
            for (int i = 0; i < nNewOverviews; i++)
12✔
970
            {
971
                MEMRasterBand *poMEMOvrBand =
972
                    cpl::down_cast<MEMRasterBand *>(papoOverviewBands[i]);
7✔
973
                if (!(poMEMOvrBand->poMask != nullptr &&
7✔
974
                      poMEMOvrBand->poMask.IsOwned()) &&
14✔
975
                    (poMEMOvrBand->nMaskFlags & GMF_PER_DATASET) == 0)
7✔
976
                {
977
                    poMEMOvrBand->CreateMaskBand(poMEMBand->nMaskFlags);
7✔
978
                }
979
                papoMaskOverviewBands[i] = poMEMOvrBand->GetMaskBand();
7✔
980
            }
981

982
            void *pScaledProgress = GDALCreateScaledProgress(
10✔
983
                1.0 * iBand / nBands, 1.0 * (iBand + 0.5) / nBands, pfnProgress,
5✔
984
                pProgressData);
985

986
            MEMRasterBand *poMaskBand =
987
                cpl::down_cast<MEMRasterBand *>(poBand->GetMaskBand());
5✔
988
            // Make the mask band to be its own mask, similarly to what is
989
            // done for alpha bands in GDALRegenerateOverviews() (#5640)
990
            poMaskBand->InvalidateMaskBand();
5✔
991
            poMaskBand->poMask.resetNotOwned(poMaskBand);
5✔
992
            poMaskBand->nMaskFlags = 0;
5✔
993
            eErr = GDALRegenerateOverviewsEx(
5✔
994
                GDALRasterBand::ToHandle(poMaskBand), nNewOverviews,
995
                reinterpret_cast<GDALRasterBandH *>(papoMaskOverviewBands),
996
                pszResampling, GDALScaledProgress, pScaledProgress,
997
                papszOptions);
998
            poMaskBand->InvalidateMaskBand();
5✔
999
            GDALDestroyScaledProgress(pScaledProgress);
5✔
1000
        }
1001

1002
        // Generate overview of bands *AFTER* mask overviews
1003
        if (nNewOverviews > 0 && eErr == CE_None)
215✔
1004
        {
1005
            void *pScaledProgress = GDALCreateScaledProgress(
645✔
1006
                1.0 * (iBand + (bMustGenerateMaskOvr ? 0.5 : 1)) / nBands,
215✔
1007
                1.0 * (iBand + 1) / nBands, pfnProgress, pProgressData);
215✔
1008
            eErr = GDALRegenerateOverviewsEx(
215✔
1009
                GDALRasterBand::ToHandle(poBand), nNewOverviews,
1010
                reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
1011
                pszResampling, GDALScaledProgress, pScaledProgress,
1012
                papszOptions);
1013
            GDALDestroyScaledProgress(pScaledProgress);
215✔
1014
        }
1015
    }
1016

1017
    /* -------------------------------------------------------------------- */
1018
    /*      Cleanup                                                         */
1019
    /* -------------------------------------------------------------------- */
1020
    CPLFree(papoOverviewBands);
159✔
1021
    CPLFree(papoMaskOverviewBands);
159✔
1022
    CPLFree(pahBands);
159✔
1023

1024
    return eErr;
159✔
1025
}
1026

1027
/************************************************************************/
1028
/*                         CreateMaskBand()                             */
1029
/************************************************************************/
1030

1031
CPLErr MEMDataset::CreateMaskBand(int nFlagsIn)
48✔
1032
{
1033
    GDALRasterBand *poFirstBand = GetRasterBand(1);
48✔
1034
    if (poFirstBand == nullptr)
48✔
1035
        return CE_Failure;
1✔
1036
    return poFirstBand->CreateMaskBand(nFlagsIn | GMF_PER_DATASET);
47✔
1037
}
1038

1039
/************************************************************************/
1040
/*                           CanBeCloned()                              */
1041
/************************************************************************/
1042

1043
/** Implements GDALDataset::CanBeCloned()
1044
 *
1045
 * This method is called by GDALThreadSafeDataset::Create() to determine if
1046
 * it is possible to create a thread-safe wrapper for a dataset, which involves
1047
 * the ability to Clone() it.
1048
 *
1049
 * The implementation of this method must be thread-safe.
1050
 */
1051
bool MEMDataset::CanBeCloned(int nScopeFlags, bool bCanShareState) const
100✔
1052
{
1053
    return nScopeFlags == GDAL_OF_RASTER && bCanShareState &&
200✔
1054
           typeid(this) == typeid(const MEMDataset *);
200✔
1055
}
1056

1057
/************************************************************************/
1058
/*                              Clone()                                 */
1059
/************************************************************************/
1060

1061
/** Implements GDALDataset::Clone()
1062
 *
1063
 * This method returns a new instance, identical to "this", but which shares the
1064
 * same memory buffer as "this".
1065
 *
1066
 * The implementation of this method must be thread-safe.
1067
 */
1068
std::unique_ptr<GDALDataset> MEMDataset::Clone(int nScopeFlags,
56✔
1069
                                               bool bCanShareState) const
1070
{
1071
    if (MEMDataset::CanBeCloned(nScopeFlags, bCanShareState))
56✔
1072
    {
1073
        auto poNewDS = std::make_unique<MEMDataset>();
112✔
1074
        poNewDS->poDriver = poDriver;
56✔
1075
        poNewDS->nRasterXSize = nRasterXSize;
56✔
1076
        poNewDS->nRasterYSize = nRasterYSize;
56✔
1077
        poNewDS->bGeoTransformSet = bGeoTransformSet;
56✔
1078
        poNewDS->m_gt = m_gt;
56✔
1079
        poNewDS->m_oSRS = m_oSRS;
56✔
1080
        poNewDS->m_aoGCPs = m_aoGCPs;
56✔
1081
        poNewDS->m_oGCPSRS = m_oGCPSRS;
56✔
1082
        for (const auto &poOvrDS : m_apoOverviewDS)
62✔
1083
        {
1084
            poNewDS->m_apoOverviewDS.emplace_back(
6✔
1085
                poOvrDS->Clone(nScopeFlags, bCanShareState).release());
6✔
1086
        }
1087

1088
        poNewDS->SetDescription(GetDescription());
56✔
1089
        poNewDS->oMDMD = oMDMD;
55✔
1090

1091
        // Clone bands
1092
        for (int i = 1; i <= nBands; ++i)
196✔
1093
        {
1094
            auto poSrcMEMBand =
1095
                dynamic_cast<const MEMRasterBand *>(papoBands[i - 1]);
142✔
1096
            CPLAssert(poSrcMEMBand);
142✔
1097
            auto poNewBand = std::make_unique<MEMRasterBand>(
1098
                poNewDS.get(), i, poSrcMEMBand->pabyData,
×
1099
                poSrcMEMBand->GetRasterDataType(), poSrcMEMBand->nPixelOffset,
141✔
1100
                poSrcMEMBand->nLineOffset,
142✔
1101
                /* bAssumeOwnership = */ false);
284✔
1102

1103
            poNewBand->SetDescription(poSrcMEMBand->GetDescription());
142✔
1104
            poNewBand->oMDMD = poSrcMEMBand->oMDMD;
141✔
1105

1106
            if (poSrcMEMBand->psPam)
141✔
1107
            {
1108
                poNewBand->PamInitialize();
141✔
1109
                CPLAssert(poNewBand->psPam);
142✔
1110
                poNewBand->psPam->CopyFrom(*(poSrcMEMBand->psPam));
142✔
1111
            }
1112

1113
            // Instantiates a mask band when needed.
1114
            if ((poSrcMEMBand->nMaskFlags &
142✔
1115
                 (GMF_ALL_VALID | GMF_ALPHA | GMF_NODATA)) == 0)
1116
            {
1117
                auto poSrcMaskBand = dynamic_cast<const MEMRasterBand *>(
×
1118
                    poSrcMEMBand->poMask.get());
2✔
1119
                if (poSrcMaskBand)
2✔
1120
                {
1121
                    auto poMaskBand =
1122
                        std::unique_ptr<MEMRasterBand>(new MEMRasterBand(
1123
                            poSrcMaskBand->pabyData, GDT_Byte, nRasterXSize,
2✔
1124
                            nRasterYSize, /* bOwnData = */ false));
2✔
1125
                    poMaskBand->m_bIsMask = true;
2✔
1126
                    poNewBand->poMask.reset(std::move(poMaskBand));
2✔
1127
                    poNewBand->nMaskFlags = poSrcMaskBand->nMaskFlags;
2✔
1128
                }
1129
            }
1130

1131
            poNewDS->SetBand(i, std::move(poNewBand));
142✔
1132
        }
1133

1134
        return poNewDS;
54✔
1135
    }
1136
    return GDALDataset::Clone(nScopeFlags, bCanShareState);
×
1137
}
1138

1139
/************************************************************************/
1140
/*                                Open()                                */
1141
/************************************************************************/
1142

1143
GDALDataset *MEMDataset::Open(GDALOpenInfo *poOpenInfo)
13✔
1144

1145
{
1146
    /* -------------------------------------------------------------------- */
1147
    /*      Do we have the special filename signature for MEM format        */
1148
    /*      description strings?                                            */
1149
    /* -------------------------------------------------------------------- */
1150
    if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "MEM:::") ||
13✔
1151
        poOpenInfo->fpL != nullptr)
13✔
1152
        return nullptr;
×
1153

1154
#ifndef GDAL_MEM_ENABLE_OPEN
1155
    if (!CPLTestBool(CPLGetConfigOption("GDAL_MEM_ENABLE_OPEN", "NO")))
13✔
1156
    {
1157
        CPLError(CE_Failure, CPLE_AppDefined,
6✔
1158
                 "Opening a MEM dataset with the MEM:::DATAPOINTER= syntax "
1159
                 "is no longer supported by default for security reasons. "
1160
                 "If you want to allow it, define the "
1161
                 "GDAL_MEM_ENABLE_OPEN "
1162
                 "configuration option to YES, or build GDAL with the "
1163
                 "GDAL_MEM_ENABLE_OPEN compilation definition");
1164
        return nullptr;
6✔
1165
    }
1166
#endif
1167

1168
    char **papszOptions =
1169
        CSLTokenizeStringComplex(poOpenInfo->pszFilename + 6, ",", TRUE, FALSE);
7✔
1170

1171
    /* -------------------------------------------------------------------- */
1172
    /*      Verify we have all required fields                              */
1173
    /* -------------------------------------------------------------------- */
1174
    if (CSLFetchNameValue(papszOptions, "PIXELS") == nullptr ||
7✔
1175
        CSLFetchNameValue(papszOptions, "LINES") == nullptr ||
14✔
1176
        CSLFetchNameValue(papszOptions, "DATAPOINTER") == nullptr)
7✔
1177
    {
1178
        CPLError(
×
1179
            CE_Failure, CPLE_AppDefined,
1180
            "Missing required field (one of PIXELS, LINES or DATAPOINTER).  "
1181
            "Unable to access in-memory array.");
1182

1183
        CSLDestroy(papszOptions);
×
1184
        return nullptr;
×
1185
    }
1186

1187
    /* -------------------------------------------------------------------- */
1188
    /*      Create the new MEMDataset object.                               */
1189
    /* -------------------------------------------------------------------- */
1190
    MEMDataset *poDS = new MEMDataset();
7✔
1191

1192
    poDS->nRasterXSize = atoi(CSLFetchNameValue(papszOptions, "PIXELS"));
7✔
1193
    poDS->nRasterYSize = atoi(CSLFetchNameValue(papszOptions, "LINES"));
7✔
1194
    poDS->eAccess = poOpenInfo->eAccess;
7✔
1195

1196
    /* -------------------------------------------------------------------- */
1197
    /*      Extract other information.                                      */
1198
    /* -------------------------------------------------------------------- */
1199
    const char *pszOption = CSLFetchNameValue(papszOptions, "BANDS");
7✔
1200
    int nBands = 1;
7✔
1201
    if (pszOption != nullptr)
7✔
1202
    {
1203
        nBands = atoi(pszOption);
2✔
1204
    }
1205

1206
    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
14✔
1207
        !GDALCheckBandCount(nBands, TRUE))
7✔
1208
    {
1209
        CSLDestroy(papszOptions);
×
1210
        delete poDS;
×
1211
        return nullptr;
×
1212
    }
1213

1214
    pszOption = CSLFetchNameValue(papszOptions, "DATATYPE");
7✔
1215
    GDALDataType eType = GDT_Byte;
7✔
1216
    if (pszOption != nullptr)
7✔
1217
    {
1218
        if (atoi(pszOption) > 0 && atoi(pszOption) < GDT_TypeCount)
7✔
1219
            eType = static_cast<GDALDataType>(atoi(pszOption));
×
1220
        else
1221
        {
1222
            eType = GDALGetDataTypeByName(pszOption);
7✔
1223
            if (eType == GDT_Unknown)
7✔
1224
            {
1225
                CPLError(CE_Failure, CPLE_AppDefined,
×
1226
                         "DATATYPE=%s not recognised.", pszOption);
1227
                CSLDestroy(papszOptions);
×
1228
                delete poDS;
×
1229
                return nullptr;
×
1230
            }
1231
        }
1232
    }
1233

1234
    pszOption = CSLFetchNameValue(papszOptions, "PIXELOFFSET");
7✔
1235
    GSpacing nPixelOffset;
1236
    if (pszOption == nullptr)
7✔
1237
        nPixelOffset = GDALGetDataTypeSizeBytes(eType);
5✔
1238
    else
1239
        nPixelOffset =
2✔
1240
            CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption)));
2✔
1241

1242
    pszOption = CSLFetchNameValue(papszOptions, "LINEOFFSET");
7✔
1243
    GSpacing nLineOffset = 0;
7✔
1244
    if (pszOption == nullptr)
7✔
1245
        nLineOffset = poDS->nRasterXSize * static_cast<size_t>(nPixelOffset);
5✔
1246
    else
1247
        nLineOffset =
2✔
1248
            CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption)));
2✔
1249

1250
    pszOption = CSLFetchNameValue(papszOptions, "BANDOFFSET");
7✔
1251
    GSpacing nBandOffset = 0;
7✔
1252
    if (pszOption == nullptr)
7✔
1253
        nBandOffset = nLineOffset * static_cast<size_t>(poDS->nRasterYSize);
5✔
1254
    else
1255
        nBandOffset =
2✔
1256
            CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption)));
2✔
1257

1258
    const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER");
7✔
1259
    GByte *pabyData = static_cast<GByte *>(CPLScanPointer(
14✔
1260
        pszDataPointer, static_cast<int>(strlen(pszDataPointer))));
7✔
1261

1262
    /* -------------------------------------------------------------------- */
1263
    /*      Create band information objects.                                */
1264
    /* -------------------------------------------------------------------- */
1265
    for (int iBand = 0; iBand < nBands; iBand++)
14✔
1266
    {
1267
        poDS->SetBand(iBand + 1,
7✔
1268
                      new MEMRasterBand(poDS, iBand + 1,
1269
                                        pabyData + iBand * nBandOffset, eType,
7✔
1270
                                        nPixelOffset, nLineOffset, FALSE));
7✔
1271
    }
1272

1273
    /* -------------------------------------------------------------------- */
1274
    /*      Set GeoTransform information.                                   */
1275
    /* -------------------------------------------------------------------- */
1276

1277
    pszOption = CSLFetchNameValue(papszOptions, "GEOTRANSFORM");
7✔
1278
    if (pszOption != nullptr)
7✔
1279
    {
1280
        char **values = CSLTokenizeStringComplex(pszOption, "/", TRUE, FALSE);
3✔
1281
        if (CSLCount(values) == 6)
3✔
1282
        {
1283
            GDALGeoTransform gt;
3✔
1284
            for (size_t i = 0; i < 6; ++i)
21✔
1285
            {
1286
                gt[i] = CPLScanDouble(values[i],
18✔
1287
                                      static_cast<int>(strlen(values[i])));
18✔
1288
            }
1289
            poDS->SetGeoTransform(gt);
3✔
1290
        }
1291
        CSLDestroy(values);
3✔
1292
    }
1293

1294
    /* -------------------------------------------------------------------- */
1295
    /*      Set Projection Information                                      */
1296
    /* -------------------------------------------------------------------- */
1297

1298
    pszOption = CSLFetchNameValue(papszOptions, "SPATIALREFERENCE");
7✔
1299
    if (pszOption != nullptr)
7✔
1300
    {
1301
        poDS->m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
3✔
1302
        if (poDS->m_oSRS.SetFromUserInput(pszOption) != OGRERR_NONE)
3✔
1303
        {
1304
            CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized crs: %s",
1✔
1305
                     pszOption);
1306
        }
1307
    }
1308
    /* -------------------------------------------------------------------- */
1309
    /*      Try to return a regular handle on the file.                     */
1310
    /* -------------------------------------------------------------------- */
1311
    CSLDestroy(papszOptions);
7✔
1312
    return poDS;
7✔
1313
}
1314

1315
/************************************************************************/
1316
/*                               Create()                               */
1317
/************************************************************************/
1318

1319
MEMDataset *MEMDataset::Create(const char * /* pszFilename */, int nXSize,
18,445✔
1320
                               int nYSize, int nBandsIn, GDALDataType eType,
1321
                               char **papszOptions)
1322
{
1323

1324
    /* -------------------------------------------------------------------- */
1325
    /*      Do we want a pixel interleaved buffer?  I mostly care about     */
1326
    /*      this to test pixel interleaved IO in other contexts, but it     */
1327
    /*      could be useful to create a directly accessible buffer for      */
1328
    /*      some apps.                                                      */
1329
    /* -------------------------------------------------------------------- */
1330
    bool bPixelInterleaved = false;
18,445✔
1331
    const char *pszOption = CSLFetchNameValue(papszOptions, "INTERLEAVE");
18,445✔
1332
    if (pszOption && EQUAL(pszOption, "PIXEL"))
18,446✔
1333
        bPixelInterleaved = true;
29✔
1334

1335
    /* -------------------------------------------------------------------- */
1336
    /*      First allocate band data, verifying that we can get enough      */
1337
    /*      memory.                                                         */
1338
    /* -------------------------------------------------------------------- */
1339
    const int nWordSize = GDALGetDataTypeSizeBytes(eType);
18,446✔
1340
    if (nBandsIn > 0 && nWordSize > 0 &&
18,445✔
1341
        (nBandsIn > INT_MAX / nWordSize ||
8,638✔
1342
         static_cast<GIntBig>(nXSize) * nYSize >
8,637✔
1343
             GINTBIG_MAX / (nWordSize * nBandsIn)))
8,637✔
1344
    {
1345
        CPLError(CE_Failure, CPLE_OutOfMemory, "Multiplication overflow");
3✔
1346
        return nullptr;
3✔
1347
    }
1348

1349
    const GUIntBig nGlobalBigSize =
18,442✔
1350
        static_cast<GUIntBig>(nWordSize) * nBandsIn * nXSize * nYSize;
18,442✔
1351
    const size_t nGlobalSize = static_cast<size_t>(nGlobalBigSize);
18,442✔
1352
#if SIZEOF_VOIDP == 4
1353
    if (static_cast<GUIntBig>(nGlobalSize) != nGlobalBigSize)
1354
    {
1355
        CPLError(CE_Failure, CPLE_OutOfMemory,
1356
                 "Cannot allocate " CPL_FRMT_GUIB " bytes on this platform.",
1357
                 nGlobalBigSize);
1358
        return nullptr;
1359
    }
1360
#endif
1361

1362
    std::vector<GByte *> apbyBandData;
36,883✔
1363
    if (nBandsIn > 0)
18,441✔
1364
    {
1365
        GByte *pabyData =
1366
            static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nGlobalSize));
8,635✔
1367
        if (!pabyData)
8,635✔
1368
        {
1369
            return nullptr;
2✔
1370
        }
1371

1372
        if (bPixelInterleaved)
8,633✔
1373
        {
1374
            for (int iBand = 0; iBand < nBandsIn; iBand++)
119✔
1375
            {
1376
                apbyBandData.push_back(pabyData + iBand * nWordSize);
91✔
1377
            }
1378
        }
1379
        else
1380
        {
1381
            for (int iBand = 0; iBand < nBandsIn; iBand++)
101,334✔
1382
            {
1383
                apbyBandData.push_back(
92,729✔
1384
                    pabyData +
92,729✔
1385
                    (static_cast<size_t>(nWordSize) * nXSize * nYSize) * iBand);
92,729✔
1386
            }
1387
        }
1388
    }
1389

1390
    /* -------------------------------------------------------------------- */
1391
    /*      Create the new GTiffDataset object.                             */
1392
    /* -------------------------------------------------------------------- */
1393
    MEMDataset *poDS = new MEMDataset();
18,439✔
1394

1395
    poDS->nRasterXSize = nXSize;
18,437✔
1396
    poDS->nRasterYSize = nYSize;
18,437✔
1397
    poDS->eAccess = GA_Update;
18,437✔
1398

1399
    const char *pszPixelType = CSLFetchNameValue(papszOptions, "PIXELTYPE");
18,437✔
1400
    if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
18,435✔
1401
        poDS->SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE");
×
1402

1403
    if (bPixelInterleaved)
18,434✔
1404
        poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
28✔
1405
    else
1406
        poDS->SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE");
18,406✔
1407

1408
    /* -------------------------------------------------------------------- */
1409
    /*      Create band information objects.                                */
1410
    /* -------------------------------------------------------------------- */
1411
    for (int iBand = 0; iBand < nBandsIn; iBand++)
111,259✔
1412
    {
1413
        MEMRasterBand *poNewBand = nullptr;
92,820✔
1414

1415
        if (bPixelInterleaved)
92,820✔
1416
            poNewBand = new MEMRasterBand(
91✔
1417
                poDS, iBand + 1, apbyBandData[iBand], eType,
91✔
1418
                cpl::fits_on<int>(nWordSize * nBandsIn), 0, iBand == 0);
91✔
1419
        else
1420
            poNewBand = new MEMRasterBand(poDS, iBand + 1, apbyBandData[iBand],
185,457✔
1421
                                          eType, 0, 0, iBand == 0);
92,729✔
1422

1423
        poDS->SetBand(iBand + 1, poNewBand);
92,819✔
1424
    }
1425

1426
    /* -------------------------------------------------------------------- */
1427
    /*      Try to return a regular handle on the file.                     */
1428
    /* -------------------------------------------------------------------- */
1429
    return poDS;
18,439✔
1430
}
1431

1432
GDALDataset *MEMDataset::CreateBase(const char *pszFilename, int nXSize,
9,316✔
1433
                                    int nYSize, int nBandsIn,
1434
                                    GDALDataType eType, char **papszOptions)
1435
{
1436
    return Create(pszFilename, nXSize, nYSize, nBandsIn, eType, papszOptions);
9,316✔
1437
}
1438

1439
/************************************************************************/
1440
/*                        ~MEMAttributeHolder()                         */
1441
/************************************************************************/
1442

1443
MEMAttributeHolder::~MEMAttributeHolder() = default;
1444

1445
/************************************************************************/
1446
/*                          RenameAttribute()                           */
1447
/************************************************************************/
1448

1449
bool MEMAttributeHolder::RenameAttribute(const std::string &osOldName,
10✔
1450
                                         const std::string &osNewName)
1451
{
1452
    if (m_oMapAttributes.find(osNewName) != m_oMapAttributes.end())
10✔
1453
    {
1454
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
1455
                 "An attribute with same name already exists");
1456
        return false;
2✔
1457
    }
1458
    auto oIter = m_oMapAttributes.find(osOldName);
8✔
1459
    if (oIter == m_oMapAttributes.end())
8✔
1460
    {
1461
        CPLAssert(false);
×
1462
        return false;
1463
    }
1464
    auto poAttr = std::move(oIter->second);
8✔
1465
    m_oMapAttributes.erase(oIter);
8✔
1466
    m_oMapAttributes[osNewName] = std::move(poAttr);
8✔
1467
    return true;
8✔
1468
}
1469

1470
/************************************************************************/
1471
/*                           GetMDArrayNames()                          */
1472
/************************************************************************/
1473

1474
std::vector<std::string> MEMGroup::GetMDArrayNames(CSLConstList) const
45✔
1475
{
1476
    if (!CheckValidAndErrorOutIfNot())
45✔
1477
        return {};
2✔
1478
    std::vector<std::string> names;
86✔
1479
    for (const auto &iter : m_oMapMDArrays)
93✔
1480
        names.push_back(iter.first);
50✔
1481
    return names;
43✔
1482
}
1483

1484
/************************************************************************/
1485
/*                             OpenMDArray()                            */
1486
/************************************************************************/
1487

1488
std::shared_ptr<GDALMDArray> MEMGroup::OpenMDArray(const std::string &osName,
180✔
1489
                                                   CSLConstList) const
1490
{
1491
    if (!CheckValidAndErrorOutIfNot())
180✔
1492
        return nullptr;
×
1493
    auto oIter = m_oMapMDArrays.find(osName);
180✔
1494
    if (oIter != m_oMapMDArrays.end())
180✔
1495
        return oIter->second;
152✔
1496
    return nullptr;
28✔
1497
}
1498

1499
/************************************************************************/
1500
/*                            GetGroupNames()                           */
1501
/************************************************************************/
1502

1503
std::vector<std::string> MEMGroup::GetGroupNames(CSLConstList) const
62✔
1504
{
1505
    if (!CheckValidAndErrorOutIfNot())
62✔
1506
        return {};
×
1507
    std::vector<std::string> names;
124✔
1508
    for (const auto &iter : m_oMapGroups)
103✔
1509
        names.push_back(iter.first);
41✔
1510
    return names;
62✔
1511
}
1512

1513
/************************************************************************/
1514
/*                              OpenGroup()                             */
1515
/************************************************************************/
1516

1517
std::shared_ptr<GDALGroup> MEMGroup::OpenGroup(const std::string &osName,
67✔
1518
                                               CSLConstList) const
1519
{
1520
    if (!CheckValidAndErrorOutIfNot())
67✔
1521
        return nullptr;
×
1522
    auto oIter = m_oMapGroups.find(osName);
67✔
1523
    if (oIter != m_oMapGroups.end())
67✔
1524
        return oIter->second;
57✔
1525
    return nullptr;
10✔
1526
}
1527

1528
/************************************************************************/
1529
/*                              Create()                                */
1530
/************************************************************************/
1531

1532
/*static*/
1533
std::shared_ptr<MEMGroup> MEMGroup::Create(const std::string &osParentName,
2,933✔
1534
                                           const char *pszName)
1535
{
1536
    auto newGroup(
1537
        std::shared_ptr<MEMGroup>(new MEMGroup(osParentName, pszName)));
2,933✔
1538
    newGroup->SetSelf(newGroup);
2,933✔
1539
    if (osParentName.empty())
2,933✔
1540
        newGroup->m_poRootGroupWeak = newGroup;
155✔
1541
    return newGroup;
2,933✔
1542
}
1543

1544
/************************************************************************/
1545
/*                             CreateGroup()                            */
1546
/************************************************************************/
1547

1548
std::shared_ptr<GDALGroup> MEMGroup::CreateGroup(const std::string &osName,
33✔
1549
                                                 CSLConstList /*papszOptions*/)
1550
{
1551
    if (!CheckValidAndErrorOutIfNot())
33✔
1552
        return nullptr;
×
1553
    if (osName.empty())
33✔
1554
    {
1555
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
1556
                 "Empty group name not supported");
1557
        return nullptr;
1✔
1558
    }
1559
    if (m_oMapGroups.find(osName) != m_oMapGroups.end())
32✔
1560
    {
1561
        CPLError(CE_Failure, CPLE_AppDefined,
×
1562
                 "A group with same name already exists");
1563
        return nullptr;
×
1564
    }
1565
    auto newGroup = MEMGroup::Create(GetFullName(), osName.c_str());
64✔
1566
    newGroup->m_pParent = std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock());
32✔
1567
    newGroup->m_poRootGroupWeak = m_poRootGroupWeak;
32✔
1568
    m_oMapGroups[osName] = newGroup;
32✔
1569
    return newGroup;
32✔
1570
}
1571

1572
/************************************************************************/
1573
/*                             DeleteGroup()                            */
1574
/************************************************************************/
1575

1576
bool MEMGroup::DeleteGroup(const std::string &osName,
2✔
1577
                           CSLConstList /*papszOptions*/)
1578
{
1579
    if (!CheckValidAndErrorOutIfNot())
2✔
1580
        return false;
×
1581
    auto oIter = m_oMapGroups.find(osName);
2✔
1582
    if (oIter == m_oMapGroups.end())
2✔
1583
    {
1584
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
1585
                 "Group %s is not a sub-group of this group", osName.c_str());
1586
        return false;
1✔
1587
    }
1588

1589
    oIter->second->Deleted();
1✔
1590
    m_oMapGroups.erase(oIter);
1✔
1591
    return true;
1✔
1592
}
1593

1594
/************************************************************************/
1595
/*                       NotifyChildrenOfDeletion()                     */
1596
/************************************************************************/
1597

1598
void MEMGroup::NotifyChildrenOfDeletion()
16✔
1599
{
1600
    for (const auto &oIter : m_oMapGroups)
17✔
1601
        oIter.second->ParentDeleted();
1✔
1602
    for (const auto &oIter : m_oMapMDArrays)
17✔
1603
        oIter.second->ParentDeleted();
1✔
1604
    for (const auto &oIter : m_oMapAttributes)
37✔
1605
        oIter.second->ParentDeleted();
21✔
1606
    for (const auto &oIter : m_oMapDimensions)
16✔
1607
        oIter.second->ParentDeleted();
×
1608
}
16✔
1609

1610
/************************************************************************/
1611
/*                            CreateMDArray()                           */
1612
/************************************************************************/
1613

1614
std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray(
231✔
1615
    const std::string &osName,
1616
    const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1617
    const GDALExtendedDataType &oType, void *pData, CSLConstList papszOptions)
1618
{
1619
    if (!CheckValidAndErrorOutIfNot())
231✔
1620
        return nullptr;
×
1621
    if (osName.empty())
231✔
1622
    {
1623
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
1624
                 "Empty array name not supported");
1625
        return nullptr;
1✔
1626
    }
1627
    if (m_oMapMDArrays.find(osName) != m_oMapMDArrays.end())
230✔
1628
    {
1629
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
1630
                 "An array with same name already exists");
1631
        return nullptr;
1✔
1632
    }
1633
    auto newArray(
1634
        MEMMDArray::Create(GetFullName(), osName, aoDimensions, oType));
458✔
1635

1636
    GByte *pabyData = nullptr;
229✔
1637
    std::vector<GPtrDiff_t> anStrides;
458✔
1638
    if (pData)
229✔
1639
    {
1640
        pabyData = static_cast<GByte *>(pData);
20✔
1641
        const char *pszStrides = CSLFetchNameValue(papszOptions, "STRIDES");
20✔
1642
        if (pszStrides)
20✔
1643
        {
1644
            CPLStringList aosStrides(CSLTokenizeString2(pszStrides, ",", 0));
20✔
1645
            if (static_cast<size_t>(aosStrides.size()) != aoDimensions.size())
20✔
1646
            {
1647
                CPLError(CE_Failure, CPLE_AppDefined,
×
1648
                         "Invalid number of strides");
1649
                return nullptr;
×
1650
            }
1651
            for (int i = 0; i < aosStrides.size(); i++)
60✔
1652
            {
1653
                const auto nStride = CPLAtoGIntBig(aosStrides[i]);
40✔
1654
                anStrides.push_back(static_cast<GPtrDiff_t>(nStride));
40✔
1655
            }
1656
        }
1657
    }
1658
    if (!newArray->Init(pabyData, anStrides))
229✔
1659
        return nullptr;
2✔
1660

1661
    for (auto &poDim : newArray->GetDimensions())
616✔
1662
    {
1663
        const auto dim = std::dynamic_pointer_cast<MEMDimension>(poDim);
778✔
1664
        if (dim)
389✔
1665
            dim->RegisterUsingArray(newArray.get());
384✔
1666
    }
1667

1668
    newArray->RegisterGroup(m_pSelf);
227✔
1669
    m_oMapMDArrays[osName] = newArray;
227✔
1670
    return newArray;
227✔
1671
}
1672

1673
std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray(
211✔
1674
    const std::string &osName,
1675
    const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1676
    const GDALExtendedDataType &oType, CSLConstList papszOptions)
1677
{
1678
    void *pData = nullptr;
211✔
1679
    const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER");
211✔
1680
    if (pszDataPointer)
211✔
1681
    {
1682
        // Will not work on architectures with "capability pointers"
1683
        pData = CPLScanPointer(pszDataPointer,
×
1684
                               static_cast<int>(strlen(pszDataPointer)));
×
1685
    }
1686
    return CreateMDArray(osName, aoDimensions, oType, pData, papszOptions);
211✔
1687
}
1688

1689
/************************************************************************/
1690
/*                           DeleteMDArray()                            */
1691
/************************************************************************/
1692

1693
bool MEMGroup::DeleteMDArray(const std::string &osName,
2✔
1694
                             CSLConstList /*papszOptions*/)
1695
{
1696
    if (!CheckValidAndErrorOutIfNot())
2✔
1697
        return false;
×
1698
    auto oIter = m_oMapMDArrays.find(osName);
2✔
1699
    if (oIter == m_oMapMDArrays.end())
2✔
1700
    {
1701
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
1702
                 "Array %s is not an array of this group", osName.c_str());
1703
        return false;
1✔
1704
    }
1705

1706
    oIter->second->Deleted();
1✔
1707
    m_oMapMDArrays.erase(oIter);
1✔
1708
    return true;
1✔
1709
}
1710

1711
/************************************************************************/
1712
/*                      MEMGroupCreateMDArray()                         */
1713
/************************************************************************/
1714

1715
// Used by NUMPYMultiDimensionalDataset
1716
std::shared_ptr<GDALMDArray> MEMGroupCreateMDArray(
20✔
1717
    GDALGroup *poGroup, const std::string &osName,
1718
    const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1719
    const GDALExtendedDataType &oDataType, void *pData,
1720
    CSLConstList papszOptions)
1721
{
1722
    auto poMemGroup = dynamic_cast<MEMGroup *>(poGroup);
20✔
1723
    if (!poMemGroup)
20✔
1724
    {
1725
        CPLError(CE_Failure, CPLE_AppDefined,
×
1726
                 "MEMGroupCreateMDArray(): poGroup not of type MEMGroup");
1727
        return nullptr;
×
1728
    }
1729
    return poMemGroup->CreateMDArray(osName, aoDimensions, oDataType, pData,
1730
                                     papszOptions);
20✔
1731
}
1732

1733
/************************************************************************/
1734
/*                            GetAttribute()                            */
1735
/************************************************************************/
1736

1737
std::shared_ptr<GDALAttribute>
1738
MEMGroup::GetAttribute(const std::string &osName) const
136✔
1739
{
1740
    if (!CheckValidAndErrorOutIfNot())
136✔
1741
        return nullptr;
3✔
1742
    auto oIter = m_oMapAttributes.find(osName);
133✔
1743
    if (oIter != m_oMapAttributes.end())
133✔
1744
        return oIter->second;
116✔
1745
    return nullptr;
17✔
1746
}
1747

1748
/************************************************************************/
1749
/*                            GetAttributes()                           */
1750
/************************************************************************/
1751

1752
std::vector<std::shared_ptr<GDALAttribute>>
1753
MEMGroup::GetAttributes(CSLConstList) const
6,205✔
1754
{
1755
    if (!CheckValidAndErrorOutIfNot())
6,205✔
1756
        return {};
6✔
1757
    std::vector<std::shared_ptr<GDALAttribute>> oRes;
12,398✔
1758
    for (const auto &oIter : m_oMapAttributes)
7,660✔
1759
    {
1760
        oRes.push_back(oIter.second);
1,461✔
1761
    }
1762
    return oRes;
6,199✔
1763
}
1764

1765
/************************************************************************/
1766
/*                            GetDimensions()                           */
1767
/************************************************************************/
1768

1769
std::vector<std::shared_ptr<GDALDimension>>
1770
MEMGroup::GetDimensions(CSLConstList) const
62✔
1771
{
1772
    if (!CheckValidAndErrorOutIfNot())
62✔
1773
        return {};
×
1774
    std::vector<std::shared_ptr<GDALDimension>> oRes;
124✔
1775
    for (const auto &oIter : m_oMapDimensions)
229✔
1776
    {
1777
        oRes.push_back(oIter.second);
167✔
1778
    }
1779
    return oRes;
62✔
1780
}
1781

1782
/************************************************************************/
1783
/*                           CreateAttribute()                          */
1784
/************************************************************************/
1785

1786
std::shared_ptr<GDALAttribute>
1787
MEMGroup::CreateAttribute(const std::string &osName,
546✔
1788
                          const std::vector<GUInt64> &anDimensions,
1789
                          const GDALExtendedDataType &oDataType, CSLConstList)
1790
{
1791
    if (!CheckValidAndErrorOutIfNot())
546✔
1792
        return nullptr;
×
1793
    if (osName.empty())
546✔
1794
    {
1795
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
1796
                 "Empty attribute name not supported");
1797
        return nullptr;
1✔
1798
    }
1799
    if (m_oMapAttributes.find(osName) != m_oMapAttributes.end())
545✔
1800
    {
1801
        CPLError(CE_Failure, CPLE_AppDefined,
×
1802
                 "An attribute with same name already exists");
1803
        return nullptr;
×
1804
    }
1805
    auto newAttr(MEMAttribute::Create(
1806
        std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()), osName,
1,090✔
1807
        anDimensions, oDataType));
1,090✔
1808
    if (!newAttr)
545✔
1809
        return nullptr;
×
1810
    m_oMapAttributes[osName] = newAttr;
545✔
1811
    return newAttr;
545✔
1812
}
1813

1814
/************************************************************************/
1815
/*                         DeleteAttribute()                            */
1816
/************************************************************************/
1817

1818
bool MEMGroup::DeleteAttribute(const std::string &osName,
26✔
1819
                               CSLConstList /*papszOptions*/)
1820
{
1821
    if (!CheckValidAndErrorOutIfNot())
26✔
1822
        return false;
×
1823
    auto oIter = m_oMapAttributes.find(osName);
26✔
1824
    if (oIter == m_oMapAttributes.end())
26✔
1825
    {
1826
        CPLError(CE_Failure, CPLE_AppDefined,
13✔
1827
                 "Attribute %s is not an attribute of this group",
1828
                 osName.c_str());
1829
        return false;
13✔
1830
    }
1831

1832
    oIter->second->Deleted();
13✔
1833
    m_oMapAttributes.erase(oIter);
13✔
1834
    return true;
13✔
1835
}
1836

1837
/************************************************************************/
1838
/*                              Rename()                                */
1839
/************************************************************************/
1840

1841
bool MEMGroup::Rename(const std::string &osNewName)
4✔
1842
{
1843
    if (!CheckValidAndErrorOutIfNot())
4✔
1844
        return false;
×
1845
    if (osNewName.empty())
4✔
1846
    {
1847
        CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
1✔
1848
        return false;
1✔
1849
    }
1850
    if (m_osName == "/")
3✔
1851
    {
1852
        CPLError(CE_Failure, CPLE_NotSupported, "Cannot rename root group");
1✔
1853
        return false;
1✔
1854
    }
1855
    auto pParent = m_pParent.lock();
4✔
1856
    if (pParent)
2✔
1857
    {
1858
        if (pParent->m_oMapGroups.find(osNewName) !=
2✔
1859
            pParent->m_oMapGroups.end())
4✔
1860
        {
1861
            CPLError(CE_Failure, CPLE_AppDefined,
1✔
1862
                     "A group with same name already exists");
1863
            return false;
1✔
1864
        }
1865
        pParent->m_oMapGroups.erase(pParent->m_oMapGroups.find(m_osName));
1✔
1866
    }
1867

1868
    BaseRename(osNewName);
1✔
1869

1870
    if (pParent)
1✔
1871
    {
1872
        CPLAssert(m_pSelf.lock());
1✔
1873
        pParent->m_oMapGroups[m_osName] = m_pSelf.lock();
1✔
1874
    }
1875

1876
    return true;
1✔
1877
}
1878

1879
/************************************************************************/
1880
/*                       NotifyChildrenOfRenaming()                     */
1881
/************************************************************************/
1882

1883
void MEMGroup::NotifyChildrenOfRenaming()
3✔
1884
{
1885
    for (const auto &oIter : m_oMapGroups)
5✔
1886
        oIter.second->ParentRenamed(m_osFullName);
2✔
1887
    for (const auto &oIter : m_oMapMDArrays)
5✔
1888
        oIter.second->ParentRenamed(m_osFullName);
2✔
1889
    for (const auto &oIter : m_oMapAttributes)
5✔
1890
        oIter.second->ParentRenamed(m_osFullName);
2✔
1891
    for (const auto &oIter : m_oMapDimensions)
4✔
1892
        oIter.second->ParentRenamed(m_osFullName);
1✔
1893
}
3✔
1894

1895
/************************************************************************/
1896
/*                          RenameDimension()                           */
1897
/************************************************************************/
1898

1899
bool MEMGroup::RenameDimension(const std::string &osOldName,
2✔
1900
                               const std::string &osNewName)
1901
{
1902
    if (m_oMapDimensions.find(osNewName) != m_oMapDimensions.end())
2✔
1903
    {
1904
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
1905
                 "A dimension with same name already exists");
1906
        return false;
1✔
1907
    }
1908
    auto oIter = m_oMapDimensions.find(osOldName);
1✔
1909
    if (oIter == m_oMapDimensions.end())
1✔
1910
    {
1911
        CPLAssert(false);
×
1912
        return false;
1913
    }
1914
    auto poDim = std::move(oIter->second);
1✔
1915
    m_oMapDimensions.erase(oIter);
1✔
1916
    m_oMapDimensions[osNewName] = std::move(poDim);
1✔
1917
    return true;
1✔
1918
}
1919

1920
/************************************************************************/
1921
/*                          RenameArray()                               */
1922
/************************************************************************/
1923

1924
bool MEMGroup::RenameArray(const std::string &osOldName,
2✔
1925
                           const std::string &osNewName)
1926
{
1927
    if (m_oMapMDArrays.find(osNewName) != m_oMapMDArrays.end())
2✔
1928
    {
1929
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
1930
                 "An array with same name already exists");
1931
        return false;
1✔
1932
    }
1933
    auto oIter = m_oMapMDArrays.find(osOldName);
1✔
1934
    if (oIter == m_oMapMDArrays.end())
1✔
1935
    {
1936
        CPLAssert(false);
×
1937
        return false;
1938
    }
1939
    auto poArray = std::move(oIter->second);
1✔
1940
    m_oMapMDArrays.erase(oIter);
1✔
1941
    m_oMapMDArrays[osNewName] = std::move(poArray);
1✔
1942
    return true;
1✔
1943
}
1944

1945
/************************************************************************/
1946
/*                          MEMAbstractMDArray()                        */
1947
/************************************************************************/
1948

1949
MEMAbstractMDArray::MEMAbstractMDArray(
922✔
1950
    const std::string &osParentName, const std::string &osName,
1951
    const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1952
    const GDALExtendedDataType &oType)
×
1953
    : GDALAbstractMDArray(osParentName, osName), m_aoDims(aoDimensions),
1954
      m_oType(oType)
922✔
1955
{
1956
}
922✔
1957

1958
/************************************************************************/
1959
/*                         ~MEMAbstractMDArray()                        */
1960
/************************************************************************/
1961

1962
MEMAbstractMDArray::~MEMAbstractMDArray()
918✔
1963
{
1964
    FreeArray();
918✔
1965
}
918✔
1966

1967
/************************************************************************/
1968
/*                              FreeArray()                             */
1969
/************************************************************************/
1970

1971
void MEMAbstractMDArray::FreeArray()
924✔
1972
{
1973
    if (m_bOwnArray)
924✔
1974
    {
1975
        if (m_oType.NeedsFreeDynamicMemory())
887✔
1976
        {
1977
            GByte *pabyPtr = m_pabyArray;
454✔
1978
            GByte *pabyEnd = m_pabyArray + m_nTotalSize;
454✔
1979
            const auto nDTSize(m_oType.GetSize());
454✔
1980
            while (pabyPtr < pabyEnd)
968✔
1981
            {
1982
                m_oType.FreeDynamicMemory(pabyPtr);
514✔
1983
                pabyPtr += nDTSize;
514✔
1984
            }
1985
        }
1986
        VSIFree(m_pabyArray);
887✔
1987
        m_pabyArray = nullptr;
887✔
1988
        m_nTotalSize = 0;
887✔
1989
        m_bOwnArray = false;
887✔
1990
    }
1991
}
924✔
1992

1993
/************************************************************************/
1994
/*                                  Init()                              */
1995
/************************************************************************/
1996

1997
bool MEMAbstractMDArray::Init(GByte *pData,
922✔
1998
                              const std::vector<GPtrDiff_t> &anStrides)
1999
{
2000
    GUInt64 nTotalSize = m_oType.GetSize();
922✔
2001
    if (!m_aoDims.empty())
922✔
2002
    {
2003
        if (anStrides.empty())
345✔
2004
        {
2005
            m_anStrides.resize(m_aoDims.size());
325✔
2006
        }
2007
        else
2008
        {
2009
            CPLAssert(anStrides.size() == m_aoDims.size());
20✔
2010
            m_anStrides = anStrides;
20✔
2011
        }
2012

2013
        // To compute strides we must proceed from the fastest varying dimension
2014
        // (the last one), and then reverse the result
2015
        for (size_t i = m_aoDims.size(); i != 0;)
904✔
2016
        {
2017
            --i;
562✔
2018
            const auto &poDim = m_aoDims[i];
562✔
2019
            auto nDimSize = poDim->GetSize();
562✔
2020
            if (nDimSize == 0)
562✔
2021
            {
2022
                CPLError(CE_Failure, CPLE_IllegalArg,
×
2023
                         "Illegal dimension size 0");
2024
                return false;
×
2025
            }
2026
            if (nTotalSize > std::numeric_limits<GUInt64>::max() / nDimSize)
562✔
2027
            {
2028
                CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
3✔
2029
                return false;
3✔
2030
            }
2031
            auto nNewSize = nTotalSize * nDimSize;
559✔
2032
            if (anStrides.empty())
559✔
2033
                m_anStrides[i] = static_cast<size_t>(nTotalSize);
519✔
2034
            nTotalSize = nNewSize;
559✔
2035
        }
2036
    }
2037

2038
    // We restrict the size of the allocation so that all elements can be
2039
    // indexed by GPtrDiff_t
2040
    if (nTotalSize >
919✔
2041
        static_cast<size_t>(std::numeric_limits<GPtrDiff_t>::max()))
919✔
2042
    {
2043
        CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
1✔
2044
        return false;
1✔
2045
    }
2046
    m_nTotalSize = static_cast<size_t>(nTotalSize);
918✔
2047
    if (pData)
918✔
2048
    {
2049
        m_pabyArray = pData;
27✔
2050
    }
2051
    else
2052
    {
2053
        m_pabyArray = static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, m_nTotalSize));
891✔
2054
        m_bOwnArray = true;
891✔
2055
    }
2056

2057
    return m_pabyArray != nullptr;
918✔
2058
}
2059

2060
/************************************************************************/
2061
/*                             FastCopy()                               */
2062
/************************************************************************/
2063

2064
template <int N>
2065
inline static void FastCopy(size_t nIters, GByte *dstPtr, const GByte *srcPtr,
211✔
2066
                            GPtrDiff_t dst_inc_offset,
2067
                            GPtrDiff_t src_inc_offset)
2068
{
2069
    if (nIters >= 8)
211✔
2070
    {
2071
#define COPY_ELT(i)                                                            \
2072
    memcpy(dstPtr + (i)*dst_inc_offset, srcPtr + (i)*src_inc_offset, N)
2073
        while (true)
2074
        {
2075
            COPY_ELT(0);
43✔
2076
            COPY_ELT(1);
43✔
2077
            COPY_ELT(2);
43✔
2078
            COPY_ELT(3);
43✔
2079
            COPY_ELT(4);
43✔
2080
            COPY_ELT(5);
43✔
2081
            COPY_ELT(6);
43✔
2082
            COPY_ELT(7);
43✔
2083
            nIters -= 8;
43✔
2084
            srcPtr += 8 * src_inc_offset;
43✔
2085
            dstPtr += 8 * dst_inc_offset;
43✔
2086
            if (nIters < 8)
43✔
2087
                break;
21✔
2088
        }
2089
        if (nIters == 0)
21✔
2090
            return;
×
2091
    }
2092
    while (true)
2093
    {
2094
        memcpy(dstPtr, srcPtr, N);
418✔
2095
        if ((--nIters) == 0)
418✔
2096
            break;
211✔
2097
        srcPtr += src_inc_offset;
207✔
2098
        dstPtr += dst_inc_offset;
207✔
2099
    }
2100
}
2101

2102
/************************************************************************/
2103
/*                             ReadWrite()                              */
2104
/************************************************************************/
2105

2106
void MEMAbstractMDArray::ReadWrite(bool bIsWrite, const size_t *count,
979✔
2107
                                   std::vector<StackReadWrite> &stack,
2108
                                   const GDALExtendedDataType &srcType,
2109
                                   const GDALExtendedDataType &dstType) const
2110
{
2111
    const auto nDims = m_aoDims.size();
979✔
2112
    const auto nDimsMinus1 = nDims - 1;
979✔
2113
    const bool bBothAreNumericDT = srcType.GetClass() == GEDTC_NUMERIC &&
1,860✔
2114
                                   dstType.GetClass() == GEDTC_NUMERIC;
881✔
2115
    const bool bSameNumericDT =
2116
        bBothAreNumericDT &&
1,848✔
2117
        srcType.GetNumericDataType() == dstType.GetNumericDataType();
869✔
2118
    const auto nSameDTSize = bSameNumericDT ? srcType.GetSize() : 0;
979✔
2119
    const bool bCanUseMemcpyLastDim =
2120
        bSameNumericDT &&
1,711✔
2121
        stack[nDimsMinus1].src_inc_offset ==
732✔
2122
            static_cast<GPtrDiff_t>(nSameDTSize) &&
2,335✔
2123
        stack[nDimsMinus1].dst_inc_offset ==
624✔
2124
            static_cast<GPtrDiff_t>(nSameDTSize);
624✔
2125
    const size_t nCopySizeLastDim =
979✔
2126
        bCanUseMemcpyLastDim ? nSameDTSize * count[nDimsMinus1] : 0;
979✔
2127
    const bool bNeedsFreeDynamicMemory =
2128
        bIsWrite && dstType.NeedsFreeDynamicMemory();
979✔
2129

2130
    auto lambdaLastDim = [&](size_t idxPtr)
76,440✔
2131
    {
2132
        auto srcPtr = stack[idxPtr].src_ptr;
76,440✔
2133
        auto dstPtr = stack[idxPtr].dst_ptr;
76,440✔
2134
        if (nCopySizeLastDim)
76,440✔
2135
        {
2136
            memcpy(dstPtr, srcPtr, nCopySizeLastDim);
75,957✔
2137
        }
2138
        else
2139
        {
2140
            size_t nIters = count[nDimsMinus1];
966✔
2141
            const auto dst_inc_offset = stack[nDimsMinus1].dst_inc_offset;
483✔
2142
            const auto src_inc_offset = stack[nDimsMinus1].src_inc_offset;
483✔
2143
            if (bSameNumericDT)
483✔
2144
            {
2145
                if (nSameDTSize == 1)
211✔
2146
                {
2147
                    FastCopy<1>(nIters, dstPtr, srcPtr, dst_inc_offset,
72✔
2148
                                src_inc_offset);
2149
                    return;
72✔
2150
                }
2151
                if (nSameDTSize == 2)
139✔
2152
                {
2153
                    FastCopy<2>(nIters, dstPtr, srcPtr, dst_inc_offset,
46✔
2154
                                src_inc_offset);
2155
                    return;
46✔
2156
                }
2157
                if (nSameDTSize == 4)
93✔
2158
                {
2159
                    FastCopy<4>(nIters, dstPtr, srcPtr, dst_inc_offset,
26✔
2160
                                src_inc_offset);
2161
                    return;
26✔
2162
                }
2163
                if (nSameDTSize == 8)
67✔
2164
                {
2165
                    FastCopy<8>(nIters, dstPtr, srcPtr, dst_inc_offset,
65✔
2166
                                src_inc_offset);
2167
                    return;
65✔
2168
                }
2169
                if (nSameDTSize == 16)
2✔
2170
                {
2171
                    FastCopy<16>(nIters, dstPtr, srcPtr, dst_inc_offset,
2✔
2172
                                 src_inc_offset);
2173
                    return;
2✔
2174
                }
2175
                CPLAssert(false);
×
2176
            }
2177
            else if (bBothAreNumericDT
544✔
2178
#if SIZEOF_VOIDP >= 8
2179
                     && src_inc_offset <= std::numeric_limits<int>::max() &&
429✔
2180
                     dst_inc_offset <= std::numeric_limits<int>::max()
157✔
2181
#endif
2182
            )
2183
            {
2184
                GDALCopyWords64(srcPtr, srcType.GetNumericDataType(),
157✔
2185
                                static_cast<int>(src_inc_offset), dstPtr,
2186
                                dstType.GetNumericDataType(),
157✔
2187
                                static_cast<int>(dst_inc_offset),
2188
                                static_cast<GPtrDiff_t>(nIters));
2189
                return;
157✔
2190
            }
2191

2192
            while (true)
2193
            {
2194
                if (bNeedsFreeDynamicMemory)
417✔
2195
                {
2196
                    dstType.FreeDynamicMemory(dstPtr);
79✔
2197
                }
2198
                GDALExtendedDataType::CopyValue(srcPtr, srcType, dstPtr,
417✔
2199
                                                dstType);
2200
                if ((--nIters) == 0)
417✔
2201
                    break;
115✔
2202
                srcPtr += src_inc_offset;
302✔
2203
                dstPtr += dst_inc_offset;
302✔
2204
            }
2205
        }
2206
    };
979✔
2207

2208
    if (nDims == 1)
979✔
2209
    {
2210
        lambdaLastDim(0);
621✔
2211
    }
2212
    else if (nDims == 2)
358✔
2213
    {
2214
        auto nIters = count[0];
127✔
2215
        while (true)
2216
        {
2217
            lambdaLastDim(0);
372✔
2218
            if ((--nIters) == 0)
372✔
2219
                break;
127✔
2220
            stack[0].src_ptr += stack[0].src_inc_offset;
245✔
2221
            stack[0].dst_ptr += stack[0].dst_inc_offset;
245✔
2222
        }
2223
    }
2224
    else if (nDims == 3)
231✔
2225
    {
2226
        stack[0].nIters = count[0];
156✔
2227
        while (true)
2228
        {
2229
            stack[1].src_ptr = stack[0].src_ptr;
257✔
2230
            stack[1].dst_ptr = stack[0].dst_ptr;
257✔
2231
            auto nIters = count[1];
257✔
2232
            while (true)
2233
            {
2234
                lambdaLastDim(1);
1,963✔
2235
                if ((--nIters) == 0)
1,963✔
2236
                    break;
257✔
2237
                stack[1].src_ptr += stack[1].src_inc_offset;
1,706✔
2238
                stack[1].dst_ptr += stack[1].dst_inc_offset;
1,706✔
2239
            }
2240
            if ((--stack[0].nIters) == 0)
257✔
2241
                break;
156✔
2242
            stack[0].src_ptr += stack[0].src_inc_offset;
101✔
2243
            stack[0].dst_ptr += stack[0].dst_inc_offset;
101✔
2244
        }
101✔
2245
    }
2246
    else
2247
    {
2248
        // Implementation valid for nDims >= 3
2249

2250
        size_t dimIdx = 0;
75✔
2251
        // Non-recursive implementation. Hence the gotos
2252
        // It might be possible to rewrite this without gotos, but I find they
2253
        // make it clearer to understand the recursive nature of the code
2254
    lbl_next_depth:
150,080✔
2255
        if (dimIdx == nDimsMinus1 - 1)
150,080✔
2256
        {
2257
            auto nIters = count[dimIdx];
51,594✔
2258
            while (true)
2259
            {
2260
                lambdaLastDim(dimIdx);
73,484✔
2261
                if ((--nIters) == 0)
73,484✔
2262
                    break;
51,594✔
2263
                stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
21,890✔
2264
                stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
21,890✔
2265
            }
2266
            // If there was a test if( dimIdx > 0 ), that would be valid for
2267
            // nDims == 2
2268
            goto lbl_return_to_caller;
51,594✔
2269
        }
2270
        else
2271
        {
2272
            stack[dimIdx].nIters = count[dimIdx];
98,486✔
2273
            while (true)
2274
            {
2275
                dimIdx++;
150,005✔
2276
                stack[dimIdx].src_ptr = stack[dimIdx - 1].src_ptr;
150,005✔
2277
                stack[dimIdx].dst_ptr = stack[dimIdx - 1].dst_ptr;
150,005✔
2278
                goto lbl_next_depth;
150,005✔
2279
            lbl_return_to_caller:
150,005✔
2280
                dimIdx--;
150,005✔
2281
                if ((--stack[dimIdx].nIters) == 0)
150,005✔
2282
                    break;
98,486✔
2283
                stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
51,519✔
2284
                stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
51,519✔
2285
            }
2286
            if (dimIdx > 0)
98,486✔
2287
                goto lbl_return_to_caller;
98,411✔
2288
        }
2289
    }
2290
}
979✔
2291

2292
/************************************************************************/
2293
/*                                   IRead()                            */
2294
/************************************************************************/
2295

2296
bool MEMAbstractMDArray::IRead(const GUInt64 *arrayStartIdx,
1,004✔
2297
                               const size_t *count, const GInt64 *arrayStep,
2298
                               const GPtrDiff_t *bufferStride,
2299
                               const GDALExtendedDataType &bufferDataType,
2300
                               void *pDstBuffer) const
2301
{
2302
    if (!CheckValidAndErrorOutIfNot())
1,004✔
2303
        return false;
×
2304

2305
    const auto nDims = m_aoDims.size();
1,004✔
2306
    if (nDims == 0)
1,004✔
2307
    {
2308
        GDALExtendedDataType::CopyValue(m_pabyArray, m_oType, pDstBuffer,
409✔
2309
                                        bufferDataType);
2310
        return true;
409✔
2311
    }
2312
    std::vector<StackReadWrite> stack(nDims);
595✔
2313
    const auto nBufferDTSize = bufferDataType.GetSize();
595✔
2314
    GPtrDiff_t startSrcOffset = 0;
595✔
2315
    for (size_t i = 0; i < nDims; i++)
1,677✔
2316
    {
2317
        startSrcOffset +=
1,082✔
2318
            static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]);
1,082✔
2319
        stack[i].src_inc_offset =
2,164✔
2320
            static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]);
1,082✔
2321
        stack[i].dst_inc_offset =
1,082✔
2322
            static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize);
1,082✔
2323
    }
2324
    stack[0].src_ptr = m_pabyArray + startSrcOffset;
595✔
2325
    stack[0].dst_ptr = static_cast<GByte *>(pDstBuffer);
595✔
2326

2327
    ReadWrite(false, count, stack, m_oType, bufferDataType);
595✔
2328
    return true;
595✔
2329
}
2330

2331
/************************************************************************/
2332
/*                                IWrite()                              */
2333
/************************************************************************/
2334

2335
bool MEMAbstractMDArray::IWrite(const GUInt64 *arrayStartIdx,
937✔
2336
                                const size_t *count, const GInt64 *arrayStep,
2337
                                const GPtrDiff_t *bufferStride,
2338
                                const GDALExtendedDataType &bufferDataType,
2339
                                const void *pSrcBuffer)
2340
{
2341
    if (!CheckValidAndErrorOutIfNot())
937✔
2342
        return false;
12✔
2343
    if (!m_bWritable)
925✔
2344
    {
2345
        CPLError(CE_Failure, CPLE_AppDefined, "Non updatable object");
2✔
2346
        return false;
2✔
2347
    }
2348

2349
    m_bModified = true;
923✔
2350

2351
    const auto nDims = m_aoDims.size();
923✔
2352
    if (nDims == 0)
923✔
2353
    {
2354
        m_oType.FreeDynamicMemory(m_pabyArray);
539✔
2355
        GDALExtendedDataType::CopyValue(pSrcBuffer, bufferDataType, m_pabyArray,
539✔
2356
                                        m_oType);
539✔
2357
        return true;
539✔
2358
    }
2359
    std::vector<StackReadWrite> stack(nDims);
384✔
2360
    const auto nBufferDTSize = bufferDataType.GetSize();
384✔
2361
    GPtrDiff_t startDstOffset = 0;
384✔
2362
    for (size_t i = 0; i < nDims; i++)
999✔
2363
    {
2364
        startDstOffset +=
615✔
2365
            static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]);
615✔
2366
        stack[i].dst_inc_offset =
1,230✔
2367
            static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]);
615✔
2368
        stack[i].src_inc_offset =
615✔
2369
            static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize);
615✔
2370
    }
2371

2372
    stack[0].dst_ptr = m_pabyArray + startDstOffset;
384✔
2373
    stack[0].src_ptr = static_cast<const GByte *>(pSrcBuffer);
384✔
2374

2375
    ReadWrite(true, count, stack, bufferDataType, m_oType);
384✔
2376
    return true;
384✔
2377
}
2378

2379
/************************************************************************/
2380
/*                               MEMMDArray()                           */
2381
/************************************************************************/
2382

2383
MEMMDArray::MEMMDArray(
248✔
2384
    const std::string &osParentName, const std::string &osName,
2385
    const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
2386
    const GDALExtendedDataType &oType)
248✔
2387
    : GDALAbstractMDArray(osParentName, osName),
2388
      MEMAbstractMDArray(osParentName, osName, aoDimensions, oType),
2389
      GDALMDArray(osParentName, osName)
248✔
2390
{
2391
}
248✔
2392

2393
/************************************************************************/
2394
/*                              ~MEMMDArray()                           */
2395
/************************************************************************/
2396

2397
MEMMDArray::~MEMMDArray()
488✔
2398
{
2399
    if (m_pabyNoData)
244✔
2400
    {
2401
        m_oType.FreeDynamicMemory(&m_pabyNoData[0]);
37✔
2402
        CPLFree(m_pabyNoData);
37✔
2403
    }
2404

2405
    for (auto &poDim : GetDimensions())
664✔
2406
    {
2407
        const auto dim = std::dynamic_pointer_cast<MEMDimension>(poDim);
840✔
2408
        if (dim)
420✔
2409
            dim->UnRegisterUsingArray(this);
400✔
2410
    }
2411
}
488✔
2412

2413
/************************************************************************/
2414
/*                          GetRawNoDataValue()                         */
2415
/************************************************************************/
2416

2417
const void *MEMMDArray::GetRawNoDataValue() const
192✔
2418
{
2419
    return m_pabyNoData;
192✔
2420
}
2421

2422
/************************************************************************/
2423
/*                          SetRawNoDataValue()                         */
2424
/************************************************************************/
2425

2426
bool MEMMDArray::SetRawNoDataValue(const void *pNoData)
42✔
2427
{
2428
    if (!CheckValidAndErrorOutIfNot())
42✔
2429
        return false;
×
2430
    if (m_pabyNoData)
42✔
2431
    {
2432
        m_oType.FreeDynamicMemory(&m_pabyNoData[0]);
4✔
2433
    }
2434

2435
    if (pNoData == nullptr)
42✔
2436
    {
2437
        CPLFree(m_pabyNoData);
1✔
2438
        m_pabyNoData = nullptr;
1✔
2439
    }
2440
    else
2441
    {
2442
        const auto nSize = m_oType.GetSize();
41✔
2443
        if (m_pabyNoData == nullptr)
41✔
2444
        {
2445
            m_pabyNoData = static_cast<GByte *>(CPLMalloc(nSize));
38✔
2446
        }
2447
        memset(m_pabyNoData, 0, nSize);
41✔
2448
        GDALExtendedDataType::CopyValue(pNoData, m_oType, m_pabyNoData,
41✔
2449
                                        m_oType);
41✔
2450
    }
2451
    return true;
42✔
2452
}
2453

2454
/************************************************************************/
2455
/*                            GetAttribute()                            */
2456
/************************************************************************/
2457

2458
std::shared_ptr<GDALAttribute>
2459
MEMMDArray::GetAttribute(const std::string &osName) const
276✔
2460
{
2461
    if (!CheckValidAndErrorOutIfNot())
276✔
2462
        return nullptr;
×
2463
    auto oIter = m_oMapAttributes.find(osName);
276✔
2464
    if (oIter != m_oMapAttributes.end())
276✔
2465
        return oIter->second;
68✔
2466
    return nullptr;
208✔
2467
}
2468

2469
/************************************************************************/
2470
/*                             GetAttributes()                          */
2471
/************************************************************************/
2472

2473
std::vector<std::shared_ptr<GDALAttribute>>
2474
MEMMDArray::GetAttributes(CSLConstList) const
58✔
2475
{
2476
    if (!CheckValidAndErrorOutIfNot())
58✔
2477
        return {};
2✔
2478
    std::vector<std::shared_ptr<GDALAttribute>> oRes;
112✔
2479
    for (const auto &oIter : m_oMapAttributes)
86✔
2480
    {
2481
        oRes.push_back(oIter.second);
30✔
2482
    }
2483
    return oRes;
56✔
2484
}
2485

2486
/************************************************************************/
2487
/*                            CreateAttribute()                         */
2488
/************************************************************************/
2489

2490
std::shared_ptr<GDALAttribute>
2491
MEMMDArray::CreateAttribute(const std::string &osName,
57✔
2492
                            const std::vector<GUInt64> &anDimensions,
2493
                            const GDALExtendedDataType &oDataType, CSLConstList)
2494
{
2495
    if (!CheckValidAndErrorOutIfNot())
57✔
2496
        return nullptr;
×
2497
    if (osName.empty())
57✔
2498
    {
2499
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
2500
                 "Empty attribute name not supported");
2501
        return nullptr;
1✔
2502
    }
2503
    if (m_oMapAttributes.find(osName) != m_oMapAttributes.end())
56✔
2504
    {
2505
        CPLError(CE_Failure, CPLE_AppDefined,
×
2506
                 "An attribute with same name already exists");
2507
        return nullptr;
×
2508
    }
2509
    auto poSelf = std::dynamic_pointer_cast<MEMMDArray>(m_pSelf.lock());
112✔
2510
    CPLAssert(poSelf);
56✔
2511
    auto newAttr(MEMAttribute::Create(poSelf, osName, anDimensions, oDataType));
112✔
2512
    if (!newAttr)
56✔
2513
        return nullptr;
×
2514
    m_oMapAttributes[osName] = newAttr;
56✔
2515
    return newAttr;
56✔
2516
}
2517

2518
/************************************************************************/
2519
/*                         DeleteAttribute()                            */
2520
/************************************************************************/
2521

2522
bool MEMMDArray::DeleteAttribute(const std::string &osName,
4✔
2523
                                 CSLConstList /*papszOptions*/)
2524
{
2525
    if (!CheckValidAndErrorOutIfNot())
4✔
2526
        return false;
×
2527
    auto oIter = m_oMapAttributes.find(osName);
4✔
2528
    if (oIter == m_oMapAttributes.end())
4✔
2529
    {
2530
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
2531
                 "Attribute %s is not an attribute of this array",
2532
                 osName.c_str());
2533
        return false;
1✔
2534
    }
2535

2536
    oIter->second->Deleted();
3✔
2537
    m_oMapAttributes.erase(oIter);
3✔
2538
    return true;
3✔
2539
}
2540

2541
/************************************************************************/
2542
/*                      GetCoordinateVariables()                        */
2543
/************************************************************************/
2544

2545
std::vector<std::shared_ptr<GDALMDArray>>
2546
MEMMDArray::GetCoordinateVariables() const
15✔
2547
{
2548
    if (!CheckValidAndErrorOutIfNot())
15✔
2549
        return {};
×
2550
    std::vector<std::shared_ptr<GDALMDArray>> ret;
30✔
2551
    const auto poCoordinates = GetAttribute("coordinates");
45✔
2552
    if (poCoordinates &&
9✔
2553
        poCoordinates->GetDataType().GetClass() == GEDTC_STRING &&
24✔
2554
        poCoordinates->GetDimensionCount() == 0)
9✔
2555
    {
2556
        const char *pszCoordinates = poCoordinates->ReadAsString();
9✔
2557
        if (pszCoordinates)
9✔
2558
        {
2559
            auto poGroup = m_poGroupWeak.lock();
18✔
2560
            if (!poGroup)
9✔
2561
            {
2562
                CPLError(CE_Failure, CPLE_AppDefined,
×
2563
                         "Cannot access coordinate variables of %s has "
2564
                         "belonging group has gone out of scope",
2565
                         GetName().c_str());
×
2566
            }
2567
            else
2568
            {
2569
                const CPLStringList aosNames(
2570
                    CSLTokenizeString2(pszCoordinates, " ", 0));
18✔
2571
                for (int i = 0; i < aosNames.size(); i++)
35✔
2572
                {
2573
                    auto poCoordinateVar = poGroup->OpenMDArray(aosNames[i]);
78✔
2574
                    if (poCoordinateVar)
26✔
2575
                    {
2576
                        ret.emplace_back(poCoordinateVar);
25✔
2577
                    }
2578
                    else
2579
                    {
2580
                        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2581
                                 "Cannot find variable corresponding to "
2582
                                 "coordinate %s",
2583
                                 aosNames[i]);
2584
                    }
2585
                }
2586
            }
2587
        }
2588
    }
2589

2590
    return ret;
15✔
2591
}
2592

2593
/************************************************************************/
2594
/*                            Resize()                                  */
2595
/************************************************************************/
2596

2597
bool MEMMDArray::Resize(const std::vector<GUInt64> &anNewDimSizes,
17✔
2598
                        CSLConstList /* papszOptions */)
2599
{
2600
    return Resize(anNewDimSizes, /*bResizeOtherArrays=*/true);
17✔
2601
}
2602

2603
bool MEMMDArray::Resize(const std::vector<GUInt64> &anNewDimSizes,
21✔
2604
                        bool bResizeOtherArrays)
2605
{
2606
    if (!CheckValidAndErrorOutIfNot())
21✔
2607
        return false;
×
2608
    if (!IsWritable())
21✔
2609
    {
2610
        CPLError(CE_Failure, CPLE_AppDefined,
×
2611
                 "Resize() not supported on read-only file");
2612
        return false;
×
2613
    }
2614
    if (!m_bOwnArray)
21✔
2615
    {
2616
        CPLError(
×
2617
            CE_Failure, CPLE_AppDefined,
2618
            "Resize() not supported on an array that does not own its memory");
2619
        return false;
×
2620
    }
2621

2622
    const auto nDimCount = GetDimensionCount();
21✔
2623
    if (anNewDimSizes.size() != nDimCount)
21✔
2624
    {
2625
        CPLError(CE_Failure, CPLE_IllegalArg,
×
2626
                 "Not expected number of values in anNewDimSizes.");
2627
        return false;
×
2628
    }
2629

2630
    auto &dims = GetDimensions();
21✔
2631
    std::vector<size_t> anDecreasedDimIdx;
42✔
2632
    std::vector<size_t> anGrownDimIdx;
42✔
2633
    std::map<GDALDimension *, GUInt64> oMapDimToSize;
42✔
2634
    for (size_t i = 0; i < nDimCount; ++i)
61✔
2635
    {
2636
        auto oIter = oMapDimToSize.find(dims[i].get());
43✔
2637
        if (oIter != oMapDimToSize.end() && oIter->second != anNewDimSizes[i])
43✔
2638
        {
2639
            CPLError(CE_Failure, CPLE_AppDefined,
2✔
2640
                     "Cannot resize a dimension referenced several times "
2641
                     "to different sizes");
2642
            return false;
3✔
2643
        }
2644
        if (anNewDimSizes[i] != dims[i]->GetSize())
41✔
2645
        {
2646
            if (anNewDimSizes[i] == 0)
22✔
2647
            {
2648
                CPLError(CE_Failure, CPLE_IllegalArg,
1✔
2649
                         "Illegal dimension size 0");
2650
                return false;
1✔
2651
            }
2652
            auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
21✔
2653
            if (!dim)
21✔
2654
            {
2655
                CPLError(
×
2656
                    CE_Failure, CPLE_AppDefined,
2657
                    "Cannot resize a dimension that is not a MEMDimension");
2658
                return false;
×
2659
            }
2660
            oMapDimToSize[dim.get()] = anNewDimSizes[i];
21✔
2661
            if (anNewDimSizes[i] < dims[i]->GetSize())
21✔
2662
            {
2663
                anDecreasedDimIdx.push_back(i);
7✔
2664
            }
2665
            else
2666
            {
2667
                anGrownDimIdx.push_back(i);
14✔
2668
            }
2669
        }
2670
        else
2671
        {
2672
            oMapDimToSize[dims[i].get()] = dims[i]->GetSize();
19✔
2673
        }
2674
    }
2675

2676
    const auto ResizeOtherArrays = [this, &anNewDimSizes, nDimCount, &dims]()
132✔
2677
    {
2678
        std::set<MEMMDArray *> oSetArrays;
20✔
2679
        std::map<GDALDimension *, GUInt64> oMapNewSize;
10✔
2680
        for (size_t i = 0; i < nDimCount; ++i)
30✔
2681
        {
2682
            if (anNewDimSizes[i] != dims[i]->GetSize())
20✔
2683
            {
2684
                auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
24✔
2685
                if (!dim)
12✔
2686
                {
2687
                    CPLAssert(false);
×
2688
                }
2689
                else
2690
                {
2691
                    oMapNewSize[dims[i].get()] = anNewDimSizes[i];
12✔
2692
                    for (const auto &poArray : dim->GetUsingArrays())
28✔
2693
                    {
2694
                        if (poArray != this)
16✔
2695
                            oSetArrays.insert(poArray);
4✔
2696
                    }
2697
                }
2698
            }
2699
        }
2700

2701
        bool bOK = true;
10✔
2702
        for (auto *poArray : oSetArrays)
14✔
2703
        {
2704
            const auto &apoOtherDims = poArray->GetDimensions();
4✔
2705
            std::vector<GUInt64> anOtherArrayNewDimSizes(
2706
                poArray->GetDimensionCount());
4✔
2707
            for (size_t i = 0; i < anOtherArrayNewDimSizes.size(); ++i)
14✔
2708
            {
2709
                auto oIter = oMapNewSize.find(apoOtherDims[i].get());
10✔
2710
                if (oIter != oMapNewSize.end())
10✔
2711
                    anOtherArrayNewDimSizes[i] = oIter->second;
4✔
2712
                else
2713
                    anOtherArrayNewDimSizes[i] = apoOtherDims[i]->GetSize();
6✔
2714
            }
2715
            if (!poArray->Resize(anOtherArrayNewDimSizes,
4✔
2716
                                 /*bResizeOtherArrays=*/false))
2717
            {
2718
                bOK = false;
×
2719
                break;
×
2720
            }
2721
        }
2722
        if (!bOK)
10✔
2723
        {
2724
            CPLError(CE_Failure, CPLE_AppDefined,
×
2725
                     "Resizing of another array referencing the same dimension "
2726
                     "as one modified on the current array failed. All arrays "
2727
                     "referencing that dimension will be invalidated.");
2728
            Invalidate();
×
2729
            for (auto *poArray : oSetArrays)
×
2730
            {
2731
                poArray->Invalidate();
×
2732
            }
2733
        }
2734

2735
        return bOK;
20✔
2736
    };
18✔
2737

2738
    // Decrease slowest varying dimension
2739
    if (anGrownDimIdx.empty() && anDecreasedDimIdx.size() == 1 &&
24✔
2740
        anDecreasedDimIdx[0] == 0)
6✔
2741
    {
2742
        CPLAssert(m_nTotalSize % dims[0]->GetSize() == 0);
4✔
2743
        const size_t nNewTotalSize = static_cast<size_t>(
4✔
2744
            (m_nTotalSize / dims[0]->GetSize()) * anNewDimSizes[0]);
4✔
2745
        if (m_oType.NeedsFreeDynamicMemory())
4✔
2746
        {
2747
            GByte *pabyPtr = m_pabyArray + nNewTotalSize;
×
2748
            GByte *pabyEnd = m_pabyArray + m_nTotalSize;
×
2749
            const auto nDTSize(m_oType.GetSize());
×
2750
            while (pabyPtr < pabyEnd)
×
2751
            {
2752
                m_oType.FreeDynamicMemory(pabyPtr);
×
2753
                pabyPtr += nDTSize;
×
2754
            }
2755
        }
2756
        // shrinking... cannot fail, and even if it does, that's ok
2757
        GByte *pabyArray = static_cast<GByte *>(
2758
            VSI_REALLOC_VERBOSE(m_pabyArray, nNewTotalSize));
4✔
2759
        if (pabyArray)
4✔
2760
            m_pabyArray = pabyArray;
4✔
2761
        m_nTotalSize = nNewTotalSize;
4✔
2762

2763
        if (bResizeOtherArrays)
4✔
2764
        {
2765
            if (!ResizeOtherArrays())
3✔
2766
                return false;
×
2767

2768
            auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[0]);
6✔
2769
            if (dim)
3✔
2770
            {
2771
                dim->SetSize(anNewDimSizes[0]);
3✔
2772
            }
2773
            else
2774
            {
2775
                CPLAssert(false);
×
2776
            }
2777
        }
2778
        return true;
4✔
2779
    }
2780

2781
    // Increase slowest varying dimension
2782
    if (anDecreasedDimIdx.empty() && anGrownDimIdx.size() == 1 &&
24✔
2783
        anGrownDimIdx[0] == 0)
10✔
2784
    {
2785
        CPLAssert(m_nTotalSize % dims[0]->GetSize() == 0);
6✔
2786
        GUInt64 nNewTotalSize64 = m_nTotalSize / dims[0]->GetSize();
6✔
2787
        if (nNewTotalSize64 >
6✔
2788
            std::numeric_limits<GUInt64>::max() / anNewDimSizes[0])
6✔
2789
        {
2790
            CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
1✔
2791
            return false;
1✔
2792
        }
2793
        nNewTotalSize64 *= anNewDimSizes[0];
5✔
2794
        // We restrict the size of the allocation so that all elements can be
2795
        // indexed by GPtrDiff_t
2796
        if (nNewTotalSize64 >
5✔
2797
            static_cast<size_t>(std::numeric_limits<GPtrDiff_t>::max()))
5✔
2798
        {
2799
            CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
×
2800
            return false;
×
2801
        }
2802
        const size_t nNewTotalSize = static_cast<size_t>(nNewTotalSize64);
5✔
2803
        GByte *pabyArray = static_cast<GByte *>(
2804
            VSI_REALLOC_VERBOSE(m_pabyArray, nNewTotalSize));
5✔
2805
        if (!pabyArray)
5✔
2806
            return false;
1✔
2807
        memset(pabyArray + m_nTotalSize, 0, nNewTotalSize - m_nTotalSize);
4✔
2808
        m_pabyArray = pabyArray;
4✔
2809
        m_nTotalSize = nNewTotalSize;
4✔
2810

2811
        if (bResizeOtherArrays)
4✔
2812
        {
2813
            if (!ResizeOtherArrays())
3✔
2814
                return false;
×
2815

2816
            auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[0]);
6✔
2817
            if (dim)
3✔
2818
            {
2819
                dim->SetSize(anNewDimSizes[0]);
3✔
2820
            }
2821
            else
2822
            {
2823
                CPLAssert(false);
×
2824
            }
2825
        }
2826
        return true;
4✔
2827
    }
2828

2829
    // General case where we modify other dimensions that the first one.
2830

2831
    // Create dummy dimensions at the new sizes
2832
    std::vector<std::shared_ptr<GDALDimension>> aoNewDims;
16✔
2833
    for (size_t i = 0; i < nDimCount; ++i)
30✔
2834
    {
2835
        aoNewDims.emplace_back(std::make_shared<MEMDimension>(
44✔
2836
            std::string(), dims[i]->GetName(), std::string(), std::string(),
44✔
2837
            anNewDimSizes[i]));
44✔
2838
    }
2839

2840
    // Create a temporary array
2841
    auto poTempMDArray =
2842
        Create(std::string(), std::string(), aoNewDims, GetDataType());
24✔
2843
    if (!poTempMDArray->Init())
8✔
2844
        return false;
2✔
2845
    std::vector<GUInt64> arrayStartIdx(nDimCount);
12✔
2846
    std::vector<size_t> count(nDimCount);
12✔
2847
    std::vector<GInt64> arrayStep(nDimCount, 1);
12✔
2848
    std::vector<GPtrDiff_t> bufferStride(nDimCount);
12✔
2849
    for (size_t i = nDimCount; i > 0;)
22✔
2850
    {
2851
        --i;
16✔
2852
        if (i == nDimCount - 1)
16✔
2853
            bufferStride[i] = 1;
6✔
2854
        else
2855
        {
2856
            bufferStride[i] = static_cast<GPtrDiff_t>(bufferStride[i + 1] *
20✔
2857
                                                      dims[i + 1]->GetSize());
10✔
2858
        }
2859
        const auto nCount = std::min(anNewDimSizes[i], dims[i]->GetSize());
16✔
2860
        count[i] = static_cast<size_t>(nCount);
16✔
2861
    }
2862
    // Copy the current content into the array with the new layout
2863
    if (!poTempMDArray->Write(arrayStartIdx.data(), count.data(),
12✔
2864
                              arrayStep.data(), bufferStride.data(),
6✔
2865
                              GetDataType(), m_pabyArray))
6✔
2866
    {
2867
        return false;
×
2868
    }
2869

2870
    // Move content of the temporary array into the current array, and
2871
    // invalidate the temporary array
2872
    FreeArray();
6✔
2873
    m_bOwnArray = true;
6✔
2874
    m_pabyArray = poTempMDArray->m_pabyArray;
6✔
2875
    m_nTotalSize = poTempMDArray->m_nTotalSize;
6✔
2876
    m_anStrides = poTempMDArray->m_anStrides;
6✔
2877

2878
    poTempMDArray->m_bOwnArray = false;
6✔
2879
    poTempMDArray->m_pabyArray = nullptr;
6✔
2880
    poTempMDArray->m_nTotalSize = 0;
6✔
2881

2882
    if (bResizeOtherArrays && !ResizeOtherArrays())
6✔
2883
        return false;
×
2884

2885
    // Update dimension size
2886
    for (size_t i = 0; i < nDimCount; ++i)
22✔
2887
    {
2888
        if (anNewDimSizes[i] != dims[i]->GetSize())
16✔
2889
        {
2890
            auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
10✔
2891
            if (dim)
5✔
2892
            {
2893
                dim->SetSize(anNewDimSizes[i]);
5✔
2894
            }
2895
            else
2896
            {
2897
                CPLAssert(false);
×
2898
            }
2899
        }
2900
    }
2901

2902
    return true;
6✔
2903
}
2904

2905
/************************************************************************/
2906
/*                              Rename()                                */
2907
/************************************************************************/
2908

2909
bool MEMMDArray::Rename(const std::string &osNewName)
3✔
2910
{
2911
    if (!CheckValidAndErrorOutIfNot())
3✔
2912
        return false;
×
2913
    if (osNewName.empty())
3✔
2914
    {
2915
        CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
1✔
2916
        return false;
1✔
2917
    }
2918

2919
    if (auto poParentGroup =
2✔
2920
            std::dynamic_pointer_cast<MEMGroup>(m_poGroupWeak.lock()))
4✔
2921
    {
2922
        if (!poParentGroup->RenameArray(m_osName, osNewName))
2✔
2923
        {
2924
            return false;
1✔
2925
        }
2926
    }
2927

2928
    BaseRename(osNewName);
1✔
2929

2930
    return true;
1✔
2931
}
2932

2933
/************************************************************************/
2934
/*                       NotifyChildrenOfRenaming()                     */
2935
/************************************************************************/
2936

2937
void MEMMDArray::NotifyChildrenOfRenaming()
3✔
2938
{
2939
    for (const auto &oIter : m_oMapAttributes)
6✔
2940
        oIter.second->ParentRenamed(m_osFullName);
3✔
2941
}
3✔
2942

2943
/************************************************************************/
2944
/*                       NotifyChildrenOfDeletion()                     */
2945
/************************************************************************/
2946

2947
void MEMMDArray::NotifyChildrenOfDeletion()
2✔
2948
{
2949
    for (const auto &oIter : m_oMapAttributes)
4✔
2950
        oIter.second->ParentDeleted();
2✔
2951
}
2✔
2952

2953
/************************************************************************/
2954
/*                            BuildDimensions()                         */
2955
/************************************************************************/
2956

2957
static std::vector<std::shared_ptr<GDALDimension>>
2958
BuildDimensions(const std::vector<GUInt64> &anDimensions)
674✔
2959
{
2960
    std::vector<std::shared_ptr<GDALDimension>> res;
674✔
2961
    for (size_t i = 0; i < anDimensions.size(); i++)
808✔
2962
    {
2963
        res.emplace_back(std::make_shared<GDALDimensionWeakIndexingVar>(
268✔
2964
            std::string(), CPLSPrintf("dim%u", static_cast<unsigned>(i)),
268✔
2965
            std::string(), std::string(), anDimensions[i]));
402✔
2966
    }
2967
    return res;
674✔
2968
}
2969

2970
/************************************************************************/
2971
/*                             MEMAttribute()                           */
2972
/************************************************************************/
2973

2974
MEMAttribute::MEMAttribute(const std::string &osParentName,
674✔
2975
                           const std::string &osName,
2976
                           const std::vector<GUInt64> &anDimensions,
2977
                           const GDALExtendedDataType &oType)
674✔
2978
    : GDALAbstractMDArray(osParentName, osName),
2979
      MEMAbstractMDArray(osParentName, osName, BuildDimensions(anDimensions),
674✔
2980
                         oType),
2981
      GDALAttribute(osParentName, osName)
1,348✔
2982
{
2983
}
674✔
2984

2985
/************************************************************************/
2986
/*                        MEMAttribute::Create()                        */
2987
/************************************************************************/
2988

2989
std::shared_ptr<MEMAttribute>
2990
MEMAttribute::Create(const std::string &osParentName, const std::string &osName,
674✔
2991
                     const std::vector<GUInt64> &anDimensions,
2992
                     const GDALExtendedDataType &oType)
2993
{
2994
    auto attr(std::shared_ptr<MEMAttribute>(
2995
        new MEMAttribute(osParentName, osName, anDimensions, oType)));
1,348✔
2996
    attr->SetSelf(attr);
674✔
2997
    if (!attr->Init())
674✔
2998
        return nullptr;
×
2999
    return attr;
674✔
3000
}
3001

3002
/************************************************************************/
3003
/*                        MEMAttribute::Create()                        */
3004
/************************************************************************/
3005

3006
std::shared_ptr<MEMAttribute> MEMAttribute::Create(
545✔
3007
    const std::shared_ptr<MEMGroup> &poParentGroup, const std::string &osName,
3008
    const std::vector<GUInt64> &anDimensions, const GDALExtendedDataType &oType)
3009
{
3010
    const std::string osParentName =
3011
        (poParentGroup && poParentGroup->GetName().empty())
545✔
3012
            ?
545✔
3013
            // Case of the ZarrAttributeGroup::m_oGroup fake group
3014
            poParentGroup->GetFullName()
525✔
3015
            : ((poParentGroup == nullptr || poParentGroup->GetFullName() == "/"
40✔
3016
                    ? "/"
605✔
3017
                    : poParentGroup->GetFullName() + "/") +
10✔
3018
               "_GLOBAL_");
1,635✔
3019
    auto attr(Create(osParentName, osName, anDimensions, oType));
1,090✔
3020
    if (!attr)
545✔
3021
        return nullptr;
×
3022
    attr->m_poParent = poParentGroup;
545✔
3023
    return attr;
545✔
3024
}
3025

3026
/************************************************************************/
3027
/*                        MEMAttribute::Create()                        */
3028
/************************************************************************/
3029

3030
std::shared_ptr<MEMAttribute> MEMAttribute::Create(
56✔
3031
    const std::shared_ptr<MEMMDArray> &poParentArray, const std::string &osName,
3032
    const std::vector<GUInt64> &anDimensions, const GDALExtendedDataType &oType)
3033
{
3034
    auto attr(
3035
        Create(poParentArray->GetFullName(), osName, anDimensions, oType));
112✔
3036
    if (!attr)
56✔
3037
        return nullptr;
×
3038
    attr->m_poParent = poParentArray;
56✔
3039
    return attr;
56✔
3040
}
3041

3042
/************************************************************************/
3043
/*                              Rename()                                */
3044
/************************************************************************/
3045

3046
bool MEMAttribute::Rename(const std::string &osNewName)
19✔
3047
{
3048
    if (!CheckValidAndErrorOutIfNot())
19✔
3049
        return false;
8✔
3050
    if (osNewName.empty())
11✔
3051
    {
3052
        CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
1✔
3053
        return false;
1✔
3054
    }
3055

3056
    if (auto poParent = m_poParent.lock())
10✔
3057
    {
3058
        if (!poParent->RenameAttribute(m_osName, osNewName))
10✔
3059
        {
3060
            return false;
2✔
3061
        }
3062
    }
3063

3064
    BaseRename(osNewName);
8✔
3065

3066
    m_bModified = true;
8✔
3067

3068
    return true;
8✔
3069
}
3070

3071
/************************************************************************/
3072
/*                             MEMDimension()                           */
3073
/************************************************************************/
3074

3075
MEMDimension::MEMDimension(const std::string &osParentName,
321✔
3076
                           const std::string &osName, const std::string &osType,
3077
                           const std::string &osDirection, GUInt64 nSize)
321✔
3078
    : GDALDimensionWeakIndexingVar(osParentName, osName, osType, osDirection,
3079
                                   nSize)
321✔
3080
{
3081
}
321✔
3082

3083
/************************************************************************/
3084
/*                        RegisterUsingArray()                          */
3085
/************************************************************************/
3086

3087
void MEMDimension::RegisterUsingArray(MEMMDArray *poArray)
384✔
3088
{
3089
    m_oSetArrays.insert(poArray);
384✔
3090
}
384✔
3091

3092
/************************************************************************/
3093
/*                        UnRegisterUsingArray()                        */
3094
/************************************************************************/
3095

3096
void MEMDimension::UnRegisterUsingArray(MEMMDArray *poArray)
400✔
3097
{
3098
    m_oSetArrays.erase(poArray);
400✔
3099
}
400✔
3100

3101
/************************************************************************/
3102
/*                                Create()                              */
3103
/************************************************************************/
3104

3105
/* static */
3106
std::shared_ptr<MEMDimension>
3107
MEMDimension::Create(const std::shared_ptr<MEMGroup> &poParentGroup,
299✔
3108
                     const std::string &osName, const std::string &osType,
3109
                     const std::string &osDirection, GUInt64 nSize)
3110
{
3111
    auto newDim(std::make_shared<MEMDimension>(
3112
        poParentGroup->GetFullName(), osName, osType, osDirection, nSize));
299✔
3113
    newDim->m_poParentGroup = poParentGroup;
299✔
3114
    return newDim;
299✔
3115
}
3116

3117
/************************************************************************/
3118
/*                             CreateDimension()                        */
3119
/************************************************************************/
3120

3121
std::shared_ptr<GDALDimension>
3122
MEMGroup::CreateDimension(const std::string &osName, const std::string &osType,
303✔
3123
                          const std::string &osDirection, GUInt64 nSize,
3124
                          CSLConstList)
3125
{
3126
    if (osName.empty())
303✔
3127
    {
3128
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
3129
                 "Empty dimension name not supported");
3130
        return nullptr;
1✔
3131
    }
3132
    if (m_oMapDimensions.find(osName) != m_oMapDimensions.end())
302✔
3133
    {
3134
        CPLError(CE_Failure, CPLE_AppDefined,
3✔
3135
                 "A dimension with same name already exists");
3136
        return nullptr;
3✔
3137
    }
3138
    auto newDim(MEMDimension::Create(
3139
        std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()), osName, osType,
598✔
3140
        osDirection, nSize));
598✔
3141
    m_oMapDimensions[osName] = newDim;
299✔
3142
    return newDim;
299✔
3143
}
3144

3145
/************************************************************************/
3146
/*                              Rename()                                */
3147
/************************************************************************/
3148

3149
bool MEMDimension::Rename(const std::string &osNewName)
3✔
3150
{
3151
    if (osNewName.empty())
3✔
3152
    {
3153
        CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
1✔
3154
        return false;
1✔
3155
    }
3156

3157
    if (auto poParentGroup = m_poParentGroup.lock())
2✔
3158
    {
3159
        if (!poParentGroup->RenameDimension(m_osName, osNewName))
2✔
3160
        {
3161
            return false;
1✔
3162
        }
3163
    }
3164

3165
    BaseRename(osNewName);
1✔
3166

3167
    return true;
1✔
3168
}
3169

3170
/************************************************************************/
3171
/*                     CreateMultiDimensional()                         */
3172
/************************************************************************/
3173

3174
GDALDataset *
3175
MEMDataset::CreateMultiDimensional(const char *pszFilename,
155✔
3176
                                   CSLConstList /*papszRootGroupOptions*/,
3177
                                   CSLConstList /*papszOptions*/)
3178
{
3179
    auto poDS = new MEMDataset();
155✔
3180

3181
    poDS->SetDescription(pszFilename);
155✔
3182
    auto poRootGroup = MEMGroup::Create(std::string(), nullptr);
155✔
3183
    poDS->m_poPrivate->m_poRootGroup = poRootGroup;
155✔
3184

3185
    return poDS;
310✔
3186
}
3187

3188
/************************************************************************/
3189
/*                          GetRootGroup()                              */
3190
/************************************************************************/
3191

3192
std::shared_ptr<GDALGroup> MEMDataset::GetRootGroup() const
7,912✔
3193
{
3194
    return m_poPrivate->m_poRootGroup;
7,912✔
3195
}
3196

3197
/************************************************************************/
3198
/*                     MEMDatasetIdentify()                             */
3199
/************************************************************************/
3200

3201
static int MEMDatasetIdentify(GDALOpenInfo *poOpenInfo)
72,325✔
3202
{
3203
    return (STARTS_WITH(poOpenInfo->pszFilename, "MEM:::") &&
72,338✔
3204
            poOpenInfo->fpL == nullptr);
72,338✔
3205
}
3206

3207
/************************************************************************/
3208
/*                       MEMDatasetDelete()                             */
3209
/************************************************************************/
3210

3211
static CPLErr MEMDatasetDelete(const char * /* fileName */)
4✔
3212
{
3213
    /* Null implementation, so that people can Delete("MEM:::") */
3214
    return CE_None;
4✔
3215
}
3216

3217
/************************************************************************/
3218
/*                            CreateLayer()                             */
3219
/************************************************************************/
3220

3221
OGRMemLayer *MEMDataset::CreateLayer(const OGRFeatureDefn &oDefn,
7✔
3222
                                     CSLConstList papszOptions)
3223
{
3224
    auto poLayer = std::make_unique<OGRMemLayer>(oDefn);
14✔
3225

3226
    if (CPLFetchBool(papszOptions, "ADVERTIZE_UTF8", false))
7✔
3227
        poLayer->SetAdvertizeUTF8(true);
1✔
3228

3229
    poLayer->SetDataset(this);
7✔
3230
    poLayer->SetFIDColumn(CSLFetchNameValueDef(papszOptions, "FID", ""));
7✔
3231

3232
    // Add layer to data source layer list.
3233
    m_apoLayers.emplace_back(std::move(poLayer));
7✔
3234
    return m_apoLayers.back().get();
14✔
3235
}
3236

3237
/************************************************************************/
3238
/*                           ICreateLayer()                             */
3239
/************************************************************************/
3240

3241
OGRLayer *MEMDataset::ICreateLayer(const char *pszLayerName,
1,293✔
3242
                                   const OGRGeomFieldDefn *poGeomFieldDefn,
3243
                                   CSLConstList papszOptions)
3244
{
3245
    // Create the layer object.
3246

3247
    const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
1,293✔
3248
    const auto poSRSIn =
3249
        poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
1,293✔
3250

3251
    OGRSpatialReference *poSRS = nullptr;
1,293✔
3252
    if (poSRSIn)
1,293✔
3253
    {
3254
        poSRS = poSRSIn->Clone();
250✔
3255
        poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
250✔
3256
    }
3257
    auto poLayer = std::make_unique<OGRMemLayer>(pszLayerName, poSRS, eType);
2,586✔
3258
    if (poSRS)
1,293✔
3259
    {
3260
        poSRS->Release();
250✔
3261
    }
3262

3263
    if (CPLFetchBool(papszOptions, "ADVERTIZE_UTF8", false))
1,293✔
3264
        poLayer->SetAdvertizeUTF8(true);
33✔
3265

3266
    poLayer->SetDataset(this);
1,293✔
3267
    poLayer->SetFIDColumn(CSLFetchNameValueDef(papszOptions, "FID", ""));
1,293✔
3268

3269
    // Add layer to data source layer list.
3270
    m_apoLayers.emplace_back(std::move(poLayer));
1,293✔
3271
    return m_apoLayers.back().get();
2,586✔
3272
}
3273

3274
/************************************************************************/
3275
/*                            DeleteLayer()                             */
3276
/************************************************************************/
3277

3278
OGRErr MEMDataset::DeleteLayer(int iLayer)
9✔
3279

3280
{
3281
    if (iLayer >= 0 && iLayer < static_cast<int>(m_apoLayers.size()))
9✔
3282
    {
3283
        m_apoLayers.erase(m_apoLayers.begin() + iLayer);
7✔
3284
        return OGRERR_NONE;
7✔
3285
    }
3286

3287
    return OGRERR_FAILURE;
2✔
3288
}
3289

3290
/************************************************************************/
3291
/*                           TestCapability()                           */
3292
/************************************************************************/
3293

3294
int MEMDataset::TestCapability(const char *pszCap)
947✔
3295

3296
{
3297
    if (EQUAL(pszCap, ODsCCreateLayer))
947✔
3298
        return TRUE;
330✔
3299
    else if (EQUAL(pszCap, ODsCDeleteLayer))
617✔
3300
        return TRUE;
1✔
3301
    else if (EQUAL(pszCap, ODsCCreateGeomFieldAfterCreateLayer))
616✔
3302
        return TRUE;
246✔
3303
    else if (EQUAL(pszCap, ODsCCurveGeometries))
370✔
3304
        return TRUE;
21✔
3305
    else if (EQUAL(pszCap, ODsCMeasuredGeometries))
349✔
3306
        return TRUE;
2✔
3307
    else if (EQUAL(pszCap, ODsCZGeometries))
347✔
3308
        return TRUE;
2✔
3309
    else if (EQUAL(pszCap, ODsCRandomLayerWrite))
345✔
3310
        return TRUE;
8✔
3311
    else if (EQUAL(pszCap, ODsCAddFieldDomain))
337✔
3312
        return TRUE;
10✔
3313
    else if (EQUAL(pszCap, ODsCDeleteFieldDomain))
327✔
3314
        return TRUE;
×
3315
    else if (EQUAL(pszCap, ODsCUpdateFieldDomain))
327✔
3316
        return TRUE;
×
3317

3318
    return GDALDataset::TestCapability(pszCap);
327✔
3319
}
3320

3321
/************************************************************************/
3322
/*                              GetLayer()                              */
3323
/************************************************************************/
3324

3325
OGRLayer *MEMDataset::GetLayer(int iLayer)
6,375✔
3326

3327
{
3328
    if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
6,375✔
3329
        return nullptr;
8✔
3330

3331
    return m_apoLayers[iLayer].get();
6,367✔
3332
}
3333

3334
/************************************************************************/
3335
/*                           AddFieldDomain()                           */
3336
/************************************************************************/
3337

3338
bool MEMDataset::AddFieldDomain(std::unique_ptr<OGRFieldDomain> &&domain,
20✔
3339
                                std::string &failureReason)
3340
{
3341
    if (GetFieldDomain(domain->GetName()) != nullptr)
20✔
3342
    {
3343
        failureReason = "A domain of identical name already exists";
1✔
3344
        return false;
1✔
3345
    }
3346
    const std::string domainName(domain->GetName());
19✔
3347
    m_oMapFieldDomains[domainName] = std::move(domain);
19✔
3348
    return true;
19✔
3349
}
3350

3351
/************************************************************************/
3352
/*                           DeleteFieldDomain()                        */
3353
/************************************************************************/
3354

3355
bool MEMDataset::DeleteFieldDomain(const std::string &name,
6✔
3356
                                   std::string &failureReason)
3357
{
3358
    const auto iter = m_oMapFieldDomains.find(name);
6✔
3359
    if (iter == m_oMapFieldDomains.end())
6✔
3360
    {
3361
        failureReason = "Domain does not exist";
2✔
3362
        return false;
2✔
3363
    }
3364

3365
    m_oMapFieldDomains.erase(iter);
4✔
3366

3367
    for (auto &poLayer : m_apoLayers)
8✔
3368
    {
3369
        for (int j = 0; j < poLayer->GetLayerDefn()->GetFieldCount(); ++j)
10✔
3370
        {
3371
            OGRFieldDefn *poFieldDefn =
3372
                poLayer->GetLayerDefn()->GetFieldDefn(j);
6✔
3373
            if (poFieldDefn->GetDomainName() == name)
6✔
3374
            {
3375
                auto oTemporaryUnsealer(poFieldDefn->GetTemporaryUnsealer());
3✔
3376
                poFieldDefn->SetDomainName(std::string());
3✔
3377
            }
3378
        }
3379
    }
3380

3381
    return true;
4✔
3382
}
3383

3384
/************************************************************************/
3385
/*                           UpdateFieldDomain()                        */
3386
/************************************************************************/
3387

3388
bool MEMDataset::UpdateFieldDomain(std::unique_ptr<OGRFieldDomain> &&domain,
3✔
3389
                                   std::string &failureReason)
3390
{
3391
    const std::string domainName(domain->GetName());
6✔
3392
    const auto iter = m_oMapFieldDomains.find(domainName);
3✔
3393
    if (iter == m_oMapFieldDomains.end())
3✔
3394
    {
3395
        failureReason = "No matching domain found";
1✔
3396
        return false;
1✔
3397
    }
3398
    m_oMapFieldDomains[domainName] = std::move(domain);
2✔
3399
    return true;
2✔
3400
}
3401

3402
/************************************************************************/
3403
/*                              ExecuteSQL()                            */
3404
/************************************************************************/
3405

3406
OGRLayer *MEMDataset::ExecuteSQL(const char *pszStatement,
925✔
3407
                                 OGRGeometry *poSpatialFilter,
3408
                                 const char *pszDialect)
3409
{
3410
    if (EQUAL(pszStatement, "PRAGMA read_only=1"))  // as used by VDV driver
925✔
3411
    {
3412
        for (auto &poLayer : m_apoLayers)
35✔
3413
            poLayer->SetUpdatable(false);
28✔
3414
        return nullptr;
7✔
3415
    }
3416
    return GDALDataset::ExecuteSQL(pszStatement, poSpatialFilter, pszDialect);
918✔
3417
}
3418

3419
/************************************************************************/
3420
/*                          GDALRegister_MEM()                          */
3421
/************************************************************************/
3422

3423
void GDALRegister_MEM()
1,911✔
3424
{
3425
    auto poDM = GetGDALDriverManager();
1,911✔
3426
    if (poDM->GetDriverByName("MEM") != nullptr)
1,911✔
3427
        return;
282✔
3428

3429
    GDALDriver *poDriver = new GDALDriver();
1,629✔
3430

3431
    poDriver->SetDescription("MEM");
1,629✔
3432
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
3433
    poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
1,629✔
3434
    poDriver->SetMetadataItem(
1,629✔
3435
        GDAL_DMD_LONGNAME,
3436
        "In Memory raster, vector and multidimensional raster");
1,629✔
3437
    poDriver->SetMetadataItem(
1,629✔
3438
        GDAL_DMD_CREATIONDATATYPES,
3439
        "Byte Int8 Int16 UInt16 Int32 UInt32 Int64 UInt64 Float32 Float64 "
3440
        "CInt16 CInt32 CFloat32 CFloat64");
1,629✔
3441
    poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES");
1,629✔
3442

3443
    poDriver->SetMetadataItem(
1,629✔
3444
        GDAL_DMD_CREATIONOPTIONLIST,
3445
        "<CreationOptionList>"
3446
        "   <Option name='INTERLEAVE' type='string-select' default='BAND'>"
3447
        "       <Value>BAND</Value>"
3448
        "       <Value>PIXEL</Value>"
3449
        "   </Option>"
3450
        "</CreationOptionList>");
1,629✔
3451

3452
    poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
1,629✔
3453
    poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
1,629✔
3454
    poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES");
1,629✔
3455
    poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
1,629✔
3456
    poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
1,629✔
3457
    poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
1,629✔
3458
    poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
1,629✔
3459
    poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
1,629✔
3460
    poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
1,629✔
3461
    poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
1,629✔
3462

3463
    poDriver->SetMetadataItem(
1,629✔
3464
        GDAL_DMD_CREATIONFIELDDATATYPES,
3465
        "Integer Integer64 Real String Date DateTime Time IntegerList "
3466
        "Integer64List RealList StringList Binary");
1,629✔
3467
    poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
1,629✔
3468
                              "WidthPrecision Nullable Default Unique "
3469
                              "Comment AlternativeName Domain");
1,629✔
3470
    poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
1,629✔
3471
                              "Name Type WidthPrecision Nullable Default "
3472
                              "Unique Domain AlternativeName Comment");
1,629✔
3473

3474
    poDriver->SetMetadataItem(
1,629✔
3475
        GDAL_DS_LAYER_CREATIONOPTIONLIST,
3476
        "<LayerCreationOptionList>"
3477
        "  <Option name='ADVERTIZE_UTF8' type='boolean' description='Whether "
3478
        "the layer will contain UTF-8 strings' default='NO'/>"
3479
        "  <Option name='FID' type='string' description="
3480
        "'Name of the FID column to create' default='' />"
3481
        "</LayerCreationOptionList>");
1,629✔
3482

3483
    poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES");
1,629✔
3484
    poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES");
1,629✔
3485

3486
    poDriver->SetMetadataItem(GDAL_DCAP_FIELD_DOMAINS, "YES");
1,629✔
3487
    poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DOMAIN_TYPES,
1,629✔
3488
                              "Coded Range Glob");
1,629✔
3489

3490
    poDriver->SetMetadataItem(GDAL_DMD_ALTER_GEOM_FIELD_DEFN_FLAGS,
1,629✔
3491
                              "Name Type Nullable SRS CoordinateEpoch");
1,629✔
3492

3493
    // Define GDAL_NO_OPEN_FOR_MEM_DRIVER macro to undefine Open() method for
3494
    // MEM driver.  Otherwise, bad user input can trigger easily a GDAL crash
3495
    // as random pointers can be passed as a string.  All code in GDAL tree
3496
    // using the MEM driver use the Create() method only, so Open() is not
3497
    // needed, except for esoteric uses.
3498
#ifndef GDAL_NO_OPEN_FOR_MEM_DRIVER
3499
    poDriver->pfnOpen = MEMDataset::Open;
1,629✔
3500
    poDriver->pfnIdentify = MEMDatasetIdentify;
1,629✔
3501
#endif
3502
    poDriver->pfnCreate = MEMDataset::CreateBase;
1,629✔
3503
    poDriver->pfnCreateMultiDimensional = MEMDataset::CreateMultiDimensional;
1,629✔
3504
    poDriver->pfnDelete = MEMDatasetDelete;
1,629✔
3505

3506
    poDM->RegisterDriver(poDriver);
1,629✔
3507
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc