Coverage Report

Created: 2025-06-22 06:59

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