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