Coverage Report

Created: 2026-02-14 06:52

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