Coverage Report

Created: 2026-07-25 06:50

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