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