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