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