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 15426 : GDALRasterBandH MEMCreateRasterBandEx(GDALDataset *poDS, int nBand,
60 : GByte *pabyData, GDALDataType eType,
61 : GSpacing nPixelOffset,
62 : GSpacing nLineOffset,
63 : int bAssumeOwnership)
64 :
65 : {
66 15426 : return GDALRasterBand::ToHandle(
67 : new MEMRasterBand(poDS, nBand, pabyData, eType, nPixelOffset,
68 30852 : nLineOffset, bAssumeOwnership));
69 : }
70 :
71 : /************************************************************************/
72 : /* MEMRasterBand() */
73 : /************************************************************************/
74 :
75 58 : MEMRasterBand::MEMRasterBand(GByte *pabyDataIn, GDALDataType eTypeIn,
76 58 : int nXSizeIn, int nYSizeIn, bool bOwnDataIn)
77 : : GDALPamRasterBand(FALSE), pabyData(pabyDataIn),
78 116 : nPixelOffset(GDALGetDataTypeSizeBytes(eTypeIn)), nLineOffset(0),
79 58 : bOwnData(bOwnDataIn)
80 : {
81 58 : eAccess = GA_Update;
82 58 : eDataType = eTypeIn;
83 58 : nRasterXSize = nXSizeIn;
84 58 : nRasterYSize = nYSizeIn;
85 58 : nBlockXSize = nXSizeIn;
86 58 : nBlockYSize = 1;
87 58 : nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize);
88 :
89 58 : PamInitializeNoParent();
90 58 : }
91 :
92 : /************************************************************************/
93 : /* MEMRasterBand() */
94 : /************************************************************************/
95 :
96 43267 : MEMRasterBand::MEMRasterBand(GDALDataset *poDSIn, int nBandIn,
97 : GByte *pabyDataIn, GDALDataType eTypeIn,
98 : GSpacing nPixelOffsetIn, GSpacing nLineOffsetIn,
99 43267 : int bAssumeOwnership, const char *pszPixelType)
100 : : GDALPamRasterBand(FALSE), pabyData(pabyDataIn),
101 : nPixelOffset(nPixelOffsetIn), nLineOffset(nLineOffsetIn),
102 43267 : bOwnData(bAssumeOwnership)
103 : {
104 43238 : poDS = poDSIn;
105 43238 : nBand = nBandIn;
106 :
107 43238 : eAccess = poDS->GetAccess();
108 :
109 43246 : eDataType = eTypeIn;
110 :
111 43246 : nBlockXSize = poDS->GetRasterXSize();
112 43238 : nBlockYSize = 1;
113 :
114 43238 : if (nPixelOffsetIn == 0)
115 39374 : nPixelOffset = GDALGetDataTypeSizeBytes(eTypeIn);
116 :
117 43238 : if (nLineOffsetIn == 0)
118 39483 : nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize);
119 :
120 43238 : if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
121 0 : SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE");
122 :
123 43238 : PamInitializeNoParent();
124 43237 : }
125 :
126 : /************************************************************************/
127 : /* ~MEMRasterBand() */
128 : /************************************************************************/
129 :
130 86668 : MEMRasterBand::~MEMRasterBand()
131 :
132 : {
133 43334 : if (bOwnData)
134 : {
135 8464 : VSIFree(pabyData);
136 : }
137 86668 : }
138 :
139 : /************************************************************************/
140 : /* IReadBlock() */
141 : /************************************************************************/
142 :
143 20412 : CPLErr MEMRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
144 : void *pImage)
145 : {
146 20412 : CPLAssert(nBlockXOff == 0);
147 :
148 20412 : const int nWordSize = GDALGetDataTypeSize(eDataType) / 8;
149 :
150 20411 : if (nPixelOffset == nWordSize)
151 : {
152 20310 : memcpy(pImage, pabyData + nLineOffset * (size_t)nBlockYOff,
153 20310 : static_cast<size_t>(nPixelOffset) * nBlockXSize);
154 : }
155 : else
156 : {
157 101 : GByte *const pabyCur =
158 101 : pabyData + nLineOffset * static_cast<size_t>(nBlockYOff);
159 :
160 10925 : 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 20411 : return CE_None;
168 : }
169 :
170 : /************************************************************************/
171 : /* IWriteBlock() */
172 : /************************************************************************/
173 :
174 67855 : CPLErr MEMRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
175 : void *pImage)
176 : {
177 67855 : CPLAssert(nBlockXOff == 0);
178 67855 : const int nWordSize = GDALGetDataTypeSize(eDataType) / 8;
179 :
180 67855 : if (nPixelOffset == nWordSize)
181 : {
182 67445 : memcpy(pabyData + nLineOffset * (size_t)nBlockYOff, pImage,
183 67445 : 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 67855 : return CE_None;
199 : }
200 :
201 : /************************************************************************/
202 : /* IRasterIO() */
203 : /************************************************************************/
204 :
205 1461600 : 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 1461600 : if (nXSize != nBufXSize || nYSize != nBufYSize)
213 : {
214 4825 : return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
215 : pData, nBufXSize, nBufYSize, eBufType,
216 : static_cast<int>(nPixelSpaceBuf),
217 420 : nLineSpaceBuf, psExtraArg);
218 : }
219 :
220 : // In case block based I/O has been done before.
221 1456770 : FlushCache(false);
222 :
223 1456300 : if (eRWFlag == GF_Read)
224 : {
225 9083110 : for (int iLine = 0; iLine < nYSize; iLine++)
226 : {
227 7766610 : GDALCopyWords(pabyData +
228 7766610 : nLineOffset *
229 7766610 : static_cast<GPtrDiff_t>(iLine + nYOff) +
230 7766610 : nXOff * nPixelOffset,
231 7766610 : eDataType, static_cast<int>(nPixelOffset),
232 : static_cast<GByte *>(pData) +
233 7766610 : nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine),
234 : eBufType, static_cast<int>(nPixelSpaceBuf), nXSize);
235 : }
236 : }
237 : else
238 : {
239 1688410 : for (int iLine = 0; iLine < nYSize; iLine++)
240 : {
241 1538880 : GDALCopyWords(static_cast<GByte *>(pData) +
242 1538880 : nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine),
243 : eBufType, static_cast<int>(nPixelSpaceBuf),
244 1538880 : pabyData +
245 1538880 : nLineOffset *
246 1538880 : static_cast<GPtrDiff_t>(iLine + nYOff) +
247 1538880 : nXOff * nPixelOffset,
248 1538880 : eDataType, static_cast<int>(nPixelOffset), nXSize);
249 : }
250 : }
251 1466040 : return CE_None;
252 : }
253 :
254 : /************************************************************************/
255 : /* IRasterIO() */
256 : /************************************************************************/
257 :
258 263926 : 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 263926 : const int eBufTypeSize = GDALGetDataTypeSize(eBufType) / 8;
267 :
268 : // Detect if we have a pixel-interleaved buffer
269 263932 : if (nXSize == nBufXSize && nYSize == nBufYSize && nBandCount == nBands &&
270 262610 : nBands > 1 && nBandSpaceBuf == eBufTypeSize &&
271 122546 : nPixelSpaceBuf == nBandSpaceBuf * nBands)
272 : {
273 613357 : const auto IsPixelInterleaveDataset = [this, nBandCount, panBandMap]()
274 : {
275 122416 : GDALDataType eDT = GDT_Unknown;
276 122416 : GByte *pabyData = nullptr;
277 122416 : GSpacing nPixelOffset = 0;
278 122416 : GSpacing nLineOffset = 0;
279 122416 : int eDTSize = 0;
280 122849 : for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
281 : {
282 122838 : if (panBandMap[iBandIndex] != iBandIndex + 1)
283 0 : return false;
284 :
285 122838 : MEMRasterBand *poBand = cpl::down_cast<MEMRasterBand *>(
286 : GetRasterBand(iBandIndex + 1));
287 122838 : if (iBandIndex == 0)
288 : {
289 122416 : eDT = poBand->GetRasterDataType();
290 122416 : pabyData = poBand->pabyData;
291 122416 : nPixelOffset = poBand->nPixelOffset;
292 122416 : nLineOffset = poBand->nLineOffset;
293 122416 : eDTSize = GDALGetDataTypeSizeBytes(eDT);
294 122416 : if (nPixelOffset != static_cast<GSpacing>(nBands) * eDTSize)
295 122005 : 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 122416 : };
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 122416 : };
339 :
340 122416 : 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 123522 : 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 262804 : if (nBufXSize != nXSize || nBufYSize != nYSize)
430 208 : return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
431 : pData, nBufXSize, nBufYSize, eBufType,
432 : nBandCount, panBandMap, nPixelSpaceBuf,
433 208 : nLineSpaceBuf, nBandSpaceBuf, psExtraArg);
434 :
435 262596 : return GDALDataset::BandBasedRasterIO(
436 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
437 : eBufType, nBandCount, panBandMap, nPixelSpaceBuf, nLineSpaceBuf,
438 262608 : nBandSpaceBuf, psExtraArg);
439 : }
440 :
441 : /************************************************************************/
442 : /* GetOverviewCount() */
443 : /************************************************************************/
444 :
445 4314 : int MEMRasterBand::GetOverviewCount()
446 : {
447 4314 : MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
448 4314 : if (poMemDS == nullptr)
449 4 : return 0;
450 4310 : return static_cast<int>(poMemDS->m_apoOverviewDS.size());
451 : }
452 :
453 : /************************************************************************/
454 : /* GetOverview() */
455 : /************************************************************************/
456 :
457 60829 : GDALRasterBand *MEMRasterBand::GetOverview(int i)
458 :
459 : {
460 60829 : MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
461 60829 : if (poMemDS == nullptr)
462 0 : return nullptr;
463 60829 : if (i < 0 || i >= static_cast<int>(poMemDS->m_apoOverviewDS.size()))
464 15 : return nullptr;
465 60771 : return poMemDS->m_apoOverviewDS[i]->GetRasterBand(nBand);
466 : }
467 :
468 : /************************************************************************/
469 : /* CreateMaskBand() */
470 : /************************************************************************/
471 :
472 57 : CPLErr MEMRasterBand::CreateMaskBand(int nFlagsIn)
473 : {
474 57 : InvalidateMaskBand();
475 :
476 57 : MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS);
477 57 : 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 56 : static_cast<GByte *>(VSI_CALLOC_VERBOSE(nRasterXSize, nRasterYSize));
487 56 : if (pabyMaskData == nullptr)
488 0 : return CE_Failure;
489 :
490 56 : nMaskFlags = nFlagsIn;
491 : auto poMemMaskBand = new MEMRasterBand(pabyMaskData, GDT_Byte, nRasterXSize,
492 56 : nRasterYSize, /* bOwnData= */ true);
493 56 : poMemMaskBand->m_bIsMask = true;
494 56 : poMask.reset(poMemMaskBand, true);
495 56 : if ((nFlagsIn & GMF_PER_DATASET) != 0 && nBand == 1 && poMemDS != nullptr)
496 : {
497 60 : for (int i = 2; i <= poMemDS->GetRasterCount(); ++i)
498 : {
499 : MEMRasterBand *poOtherBand =
500 9 : cpl::down_cast<MEMRasterBand *>(poMemDS->GetRasterBand(i));
501 9 : poOtherBand->InvalidateMaskBand();
502 9 : poOtherBand->nMaskFlags = nFlagsIn;
503 9 : poOtherBand->poMask.reset(poMask.get(), false);
504 : }
505 : }
506 56 : return CE_None;
507 : }
508 :
509 : /************************************************************************/
510 : /* IsMaskBand() */
511 : /************************************************************************/
512 :
513 332 : bool MEMRasterBand::IsMaskBand() const
514 : {
515 332 : return m_bIsMask || GDALPamRasterBand::IsMaskBand();
516 : }
517 :
518 : /************************************************************************/
519 : /* ==================================================================== */
520 : /* MEMDataset */
521 : /* ==================================================================== */
522 : /************************************************************************/
523 :
524 : /************************************************************************/
525 : /* MEMDataset() */
526 : /************************************************************************/
527 :
528 15896 : MEMDataset::MEMDataset()
529 15896 : : GDALDataset(FALSE), bGeoTransformSet(FALSE), m_poPrivate(new Private())
530 : {
531 15885 : adfGeoTransform[0] = 0.0;
532 15885 : adfGeoTransform[1] = 1.0;
533 15885 : adfGeoTransform[2] = 0.0;
534 15885 : adfGeoTransform[3] = 0.0;
535 15885 : adfGeoTransform[4] = 0.0;
536 15885 : adfGeoTransform[5] = -1.0;
537 15885 : DisableReadWriteMutex();
538 15891 : }
539 :
540 : /************************************************************************/
541 : /* ~MEMDataset() */
542 : /************************************************************************/
543 :
544 31798 : MEMDataset::~MEMDataset()
545 :
546 : {
547 15899 : const bool bSuppressOnCloseBackup = bSuppressOnClose;
548 15899 : bSuppressOnClose = true;
549 15899 : FlushCache(true);
550 15899 : bSuppressOnClose = bSuppressOnCloseBackup;
551 31798 : }
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 10754 : const OGRSpatialReference *MEMDataset::GetSpatialRef() const
577 :
578 : {
579 10754 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
580 : }
581 :
582 : /************************************************************************/
583 : /* SetSpatialRef() */
584 : /************************************************************************/
585 :
586 852 : CPLErr MEMDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
587 :
588 : {
589 852 : m_oSRS.Clear();
590 852 : if (poSRS)
591 805 : m_oSRS = *poSRS;
592 :
593 852 : return CE_None;
594 : }
595 :
596 : /************************************************************************/
597 : /* GetGeoTransform() */
598 : /************************************************************************/
599 :
600 10762 : CPLErr MEMDataset::GetGeoTransform(double *padfGeoTransform)
601 :
602 : {
603 10762 : memcpy(padfGeoTransform, adfGeoTransform, sizeof(double) * 6);
604 10762 : if (bGeoTransformSet)
605 5162 : return CE_None;
606 :
607 5600 : return CE_Failure;
608 : }
609 :
610 : /************************************************************************/
611 : /* SetGeoTransform() */
612 : /************************************************************************/
613 :
614 1538 : CPLErr MEMDataset::SetGeoTransform(double *padfGeoTransform)
615 :
616 : {
617 1538 : memcpy(adfGeoTransform, padfGeoTransform, sizeof(double) * 6);
618 1538 : bGeoTransformSet = TRUE;
619 :
620 1538 : 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 6863 : int MEMDataset::GetGCPCount()
658 :
659 : {
660 6863 : return static_cast<int>(m_aoGCPs.size());
661 : }
662 :
663 : /************************************************************************/
664 : /* GetGCPSpatialRef() */
665 : /************************************************************************/
666 :
667 146 : const OGRSpatialReference *MEMDataset::GetGCPSpatialRef() const
668 :
669 : {
670 146 : 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 1139 : CPLErr MEMDataset::AddBand(GDALDataType eType, char **papszOptions)
709 :
710 : {
711 1139 : const int nBandId = GetRasterCount() + 1;
712 1104 : const GSpacing nPixelSize = GDALGetDataTypeSizeBytes(eType);
713 1128 : 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 1127 : if (CSLFetchNameValue(papszOptions, "DATAPOINTER") == nullptr)
725 : {
726 200 : const GSpacing nTmp = nPixelSize * GetRasterXSize();
727 : GByte *pData =
728 : #if SIZEOF_VOIDP == 4
729 : (nTmp > INT_MAX) ? nullptr :
730 : #endif
731 200 : static_cast<GByte *>(VSI_CALLOC_VERBOSE(
732 : (size_t)nTmp, GetRasterYSize()));
733 :
734 200 : if (pData == nullptr)
735 : {
736 1 : return CE_Failure;
737 : }
738 :
739 199 : SetBand(nBandId,
740 : new MEMRasterBand(this, nBandId, pData, eType, nPixelSize,
741 199 : nPixelSize * GetRasterXSize(), TRUE));
742 :
743 199 : return CE_None;
744 : }
745 :
746 : /* -------------------------------------------------------------------- */
747 : /* Get layout of memory and other flags. */
748 : /* -------------------------------------------------------------------- */
749 904 : const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER");
750 1873 : GByte *pData = static_cast<GByte *>(CPLScanPointer(
751 941 : pszDataPointer, static_cast<int>(strlen(pszDataPointer))));
752 :
753 932 : const char *pszOption = CSLFetchNameValue(papszOptions, "PIXELOFFSET");
754 : GSpacing nPixelOffset;
755 922 : if (pszOption == nullptr)
756 0 : nPixelOffset = nPixelSize;
757 : else
758 922 : nPixelOffset = CPLAtoGIntBig(pszOption);
759 :
760 912 : pszOption = CSLFetchNameValue(papszOptions, "LINEOFFSET");
761 : GSpacing nLineOffset;
762 925 : if (pszOption == nullptr)
763 0 : nLineOffset = GetRasterXSize() * static_cast<size_t>(nPixelOffset);
764 : else
765 925 : nLineOffset = CPLAtoGIntBig(pszOption);
766 :
767 930 : SetBand(nBandId, new MEMRasterBand(this, nBandId, pData, eType,
768 934 : nPixelOffset, nLineOffset, FALSE));
769 :
770 930 : return CE_None;
771 : }
772 :
773 : /************************************************************************/
774 : /* AddMEMBand() */
775 : /************************************************************************/
776 :
777 12835 : void MEMDataset::AddMEMBand(GDALRasterBandH hMEMBand)
778 : {
779 12835 : auto poBand = GDALRasterBand::FromHandle(hMEMBand);
780 12835 : CPLAssert(dynamic_cast<MEMRasterBand *>(poBand) != nullptr);
781 12835 : SetBand(1 + nBands, poBand);
782 12835 : }
783 :
784 : /************************************************************************/
785 : /* IBuildOverviews() */
786 : /************************************************************************/
787 :
788 118 : 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 118 : if (nBands == 0)
796 : {
797 1 : CPLError(CE_Failure, CPLE_NotSupported, "Dataset has zero bands.");
798 1 : return CE_Failure;
799 : }
800 :
801 117 : 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 117 : if (nOverviews == 0)
810 : {
811 : // Cleanup existing overviews
812 1 : m_apoOverviewDS.clear();
813 1 : return CE_None;
814 : }
815 :
816 : /* -------------------------------------------------------------------- */
817 : /* Force cascading. Help to get accurate results when masks are */
818 : /* involved. */
819 : /* -------------------------------------------------------------------- */
820 116 : 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 115 : GDALRasterBand *poBand = GetRasterBand(1);
858 :
859 250 : for (int i = 0; i < nOverviews; i++)
860 : {
861 135 : bool bExisting = false;
862 163 : 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 135 : if (!bExisting)
884 : {
885 128 : auto poOvrDS = std::make_unique<MEMDataset>();
886 128 : poOvrDS->eAccess = GA_Update;
887 256 : poOvrDS->nRasterXSize =
888 128 : (nRasterXSize + panOverviewList[i] - 1) / panOverviewList[i];
889 256 : poOvrDS->nRasterYSize =
890 128 : (nRasterYSize + panOverviewList[i] - 1) / panOverviewList[i];
891 310 : for (int iBand = 0; iBand < nBands; iBand++)
892 : {
893 : const GDALDataType eDT =
894 182 : GetRasterBand(iBand + 1)->GetRasterDataType();
895 182 : if (poOvrDS->AddBand(eDT, nullptr) != CE_None)
896 : {
897 0 : return CE_Failure;
898 : }
899 : }
900 128 : m_apoOverviewDS.emplace_back(std::move(poOvrDS));
901 : }
902 : }
903 :
904 : /* -------------------------------------------------------------------- */
905 : /* Build band list. */
906 : /* -------------------------------------------------------------------- */
907 : GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
908 115 : CPLCalloc(sizeof(GDALRasterBand *), nBands));
909 270 : for (int i = 0; i < nBands; i++)
910 155 : pahBands[i] = GetRasterBand(panBandList[i]);
911 :
912 : /* -------------------------------------------------------------------- */
913 : /* Refresh overviews that were listed. */
914 : /* -------------------------------------------------------------------- */
915 : GDALRasterBand **papoOverviewBands =
916 115 : static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
917 : GDALRasterBand **papoMaskOverviewBands =
918 115 : static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
919 :
920 115 : CPLErr eErr = CE_None;
921 270 : for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
922 : {
923 155 : poBand = GetRasterBand(panBandList[iBand]);
924 :
925 155 : int nNewOverviews = 0;
926 344 : for (int i = 0; i < nOverviews; i++)
927 : {
928 231 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
929 : {
930 231 : GDALRasterBand *poOverview = poBand->GetOverview(j);
931 :
932 231 : int bHasNoData = FALSE;
933 231 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
934 :
935 231 : if (bHasNoData)
936 36 : poOverview->SetNoDataValue(noDataValue);
937 :
938 231 : const int nOvFactor = GDALComputeOvFactor(
939 : poOverview->GetXSize(), poBand->GetXSize(),
940 : poOverview->GetYSize(), poBand->GetYSize());
941 :
942 273 : if (nOvFactor == panOverviewList[i] ||
943 42 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
944 : poBand->GetXSize(),
945 : poBand->GetYSize()))
946 : {
947 189 : papoOverviewBands[nNewOverviews++] = poOverview;
948 189 : break;
949 : }
950 : }
951 : }
952 :
953 : // If the band has an explicit mask, we need to create overviews
954 : // for it
955 155 : MEMRasterBand *poMEMBand = cpl::down_cast<MEMRasterBand *>(poBand);
956 : const bool bMustGenerateMaskOvr =
957 204 : ((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 205 : ((poMEMBand->nMaskFlags & GMF_PER_DATASET) != 0 && iBand == 0)) &&
961 48 : dynamic_cast<MEMRasterBand *>(poBand->GetMaskBand()) != nullptr;
962 :
963 155 : 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 155 : if (nNewOverviews > 0 && eErr == CE_None)
999 : {
1000 465 : void *pScaledProgress = GDALCreateScaledProgress(
1001 155 : 1.0 * (iBand + (bMustGenerateMaskOvr ? 0.5 : 1)) / nBands,
1002 155 : 1.0 * (iBand + 1) / nBands, pfnProgress, pProgressData);
1003 155 : eErr = GDALRegenerateOverviewsEx(
1004 : (GDALRasterBandH)poBand, nNewOverviews,
1005 : (GDALRasterBandH *)papoOverviewBands, pszResampling,
1006 : GDALScaledProgress, pScaledProgress, papszOptions);
1007 155 : GDALDestroyScaledProgress(pScaledProgress);
1008 : }
1009 : }
1010 :
1011 : /* -------------------------------------------------------------------- */
1012 : /* Cleanup */
1013 : /* -------------------------------------------------------------------- */
1014 115 : CPLFree(papoOverviewBands);
1015 115 : CPLFree(papoMaskOverviewBands);
1016 115 : CPLFree(pahBands);
1017 :
1018 115 : return eErr;
1019 : }
1020 :
1021 : /************************************************************************/
1022 : /* CreateMaskBand() */
1023 : /************************************************************************/
1024 :
1025 43 : CPLErr MEMDataset::CreateMaskBand(int nFlagsIn)
1026 : {
1027 43 : GDALRasterBand *poFirstBand = GetRasterBand(1);
1028 43 : if (poFirstBand == nullptr)
1029 1 : return CE_Failure;
1030 42 : 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 42 : return nScopeFlags == GDAL_OF_RASTER && bCanShareState &&
1048 42 : 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 16 : poNewDS->m_oGCPSRS = m_oGCPSRS;
1077 22 : for (const auto &poOvrDS : m_apoOverviewDS)
1078 : {
1079 6 : poNewDS->m_apoOverviewDS.emplace_back(
1080 6 : poOvrDS->Clone(nScopeFlags, bCanShareState));
1081 : }
1082 :
1083 16 : poNewDS->SetDescription(GetDescription());
1084 16 : poNewDS->oMDMD = oMDMD;
1085 :
1086 : // Clone bands
1087 36 : for (int i = 1; i <= nBands; ++i)
1088 : {
1089 : auto poSrcMEMBand =
1090 21 : dynamic_cast<const MEMRasterBand *>(papoBands[i - 1]);
1091 21 : CPLAssert(poSrcMEMBand);
1092 : auto poNewBand = std::make_unique<MEMRasterBand>(
1093 0 : poNewDS.get(), i, poSrcMEMBand->pabyData,
1094 22 : poSrcMEMBand->GetRasterDataType(), poSrcMEMBand->nPixelOffset,
1095 21 : poSrcMEMBand->nLineOffset,
1096 43 : /* bAssumeOwnership = */ false);
1097 :
1098 22 : poNewBand->SetDescription(poSrcMEMBand->GetDescription());
1099 22 : poNewBand->oMDMD = poSrcMEMBand->oMDMD;
1100 :
1101 22 : if (poSrcMEMBand->psPam)
1102 : {
1103 22 : poNewBand->PamInitialize();
1104 22 : CPLAssert(poNewBand->psPam);
1105 22 : poNewBand->psPam->CopyFrom(*(poSrcMEMBand->psPam));
1106 : }
1107 :
1108 : // Instantiates a mask band when needed.
1109 22 : 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 22 : poNewDS->SetBand(i, std::move(poNewBand));
1126 : }
1127 :
1128 15 : 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 15604 : 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 15604 : bool bPixelInterleaved = false;
1334 15604 : const char *pszOption = CSLFetchNameValue(papszOptions, "INTERLEAVE");
1335 15602 : if (pszOption && EQUAL(pszOption, "PIXEL"))
1336 25 : bPixelInterleaved = true;
1337 :
1338 : /* -------------------------------------------------------------------- */
1339 : /* First allocate band data, verifying that we can get enough */
1340 : /* memory. */
1341 : /* -------------------------------------------------------------------- */
1342 15602 : const int nWordSize = GDALGetDataTypeSizeBytes(eType);
1343 15597 : if (nBandsIn > 0 && nWordSize > 0 &&
1344 8210 : (nBandsIn > INT_MAX / nWordSize ||
1345 8209 : (GIntBig)nXSize * nYSize > GINTBIG_MAX / (nWordSize * nBandsIn)))
1346 : {
1347 3 : CPLError(CE_Failure, CPLE_OutOfMemory, "Multiplication overflow");
1348 3 : return nullptr;
1349 : }
1350 :
1351 15594 : const GUIntBig nGlobalBigSize =
1352 15594 : static_cast<GUIntBig>(nWordSize) * nBandsIn * nXSize * nYSize;
1353 15594 : 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 31188 : std::vector<GByte *> apbyBandData;
1365 15593 : if (nBandsIn > 0)
1366 : {
1367 : GByte *pabyData =
1368 8207 : static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nGlobalSize));
1369 8207 : if (!pabyData)
1370 : {
1371 2 : return nullptr;
1372 : }
1373 :
1374 8205 : if (bPixelInterleaved)
1375 : {
1376 105 : for (int iBand = 0; iBand < nBandsIn; iBand++)
1377 : {
1378 81 : apbyBandData.push_back(pabyData + iBand * nWordSize);
1379 : }
1380 : }
1381 : else
1382 : {
1383 34754 : for (int iBand = 0; iBand < nBandsIn; iBand++)
1384 : {
1385 26573 : apbyBandData.push_back(
1386 26573 : pabyData +
1387 26573 : (static_cast<size_t>(nWordSize) * nXSize * nYSize) * iBand);
1388 : }
1389 : }
1390 : }
1391 :
1392 : /* -------------------------------------------------------------------- */
1393 : /* Create the new GTiffDataset object. */
1394 : /* -------------------------------------------------------------------- */
1395 15591 : MEMDataset *poDS = new MEMDataset();
1396 :
1397 15593 : poDS->nRasterXSize = nXSize;
1398 15593 : poDS->nRasterYSize = nYSize;
1399 15593 : poDS->eAccess = GA_Update;
1400 :
1401 15593 : const char *pszPixelType = CSLFetchNameValue(papszOptions, "PIXELTYPE");
1402 15587 : if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
1403 0 : poDS->SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE");
1404 :
1405 15587 : if (bPixelInterleaved)
1406 24 : poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
1407 :
1408 : /* -------------------------------------------------------------------- */
1409 : /* Create band information objects. */
1410 : /* -------------------------------------------------------------------- */
1411 42246 : for (int iBand = 0; iBand < nBandsIn; iBand++)
1412 : {
1413 26654 : MEMRasterBand *poNewBand = nullptr;
1414 :
1415 26654 : if (bPixelInterleaved)
1416 81 : poNewBand = new MEMRasterBand(
1417 81 : poDS, iBand + 1, apbyBandData[iBand], eType,
1418 81 : cpl::fits_on<int>(nWordSize * nBandsIn), 0, iBand == 0);
1419 : else
1420 53146 : poNewBand = new MEMRasterBand(poDS, iBand + 1, apbyBandData[iBand],
1421 26573 : eType, 0, 0, iBand == 0);
1422 :
1423 26654 : poDS->SetBand(iBand + 1, poNewBand);
1424 : }
1425 :
1426 : /* -------------------------------------------------------------------- */
1427 : /* Try to return a regular handle on the file. */
1428 : /* -------------------------------------------------------------------- */
1429 15592 : return poDS;
1430 : }
1431 :
1432 8129 : GDALDataset *MEMDataset::CreateBase(const char *pszFilename, int nXSize,
1433 : int nYSize, int nBandsIn,
1434 : GDALDataType eType, char **papszOptions)
1435 : {
1436 8129 : return Create(pszFilename, nXSize, nYSize, nBandsIn, eType, papszOptions);
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* ~MEMAttributeHolder() */
1441 : /************************************************************************/
1442 :
1443 : MEMAttributeHolder::~MEMAttributeHolder() = default;
1444 :
1445 : /************************************************************************/
1446 : /* RenameAttribute() */
1447 : /************************************************************************/
1448 :
1449 10 : bool MEMAttributeHolder::RenameAttribute(const std::string &osOldName,
1450 : const std::string &osNewName)
1451 : {
1452 10 : if (m_oMapAttributes.find(osNewName) != m_oMapAttributes.end())
1453 : {
1454 2 : CPLError(CE_Failure, CPLE_AppDefined,
1455 : "An attribute with same name already exists");
1456 2 : return false;
1457 : }
1458 8 : auto oIter = m_oMapAttributes.find(osOldName);
1459 8 : if (oIter == m_oMapAttributes.end())
1460 : {
1461 0 : CPLAssert(false);
1462 : return false;
1463 : }
1464 8 : auto poAttr = std::move(oIter->second);
1465 8 : m_oMapAttributes.erase(oIter);
1466 8 : m_oMapAttributes[osNewName] = std::move(poAttr);
1467 8 : return true;
1468 : }
1469 :
1470 : /************************************************************************/
1471 : /* GetMDArrayNames() */
1472 : /************************************************************************/
1473 :
1474 41 : std::vector<std::string> MEMGroup::GetMDArrayNames(CSLConstList) const
1475 : {
1476 41 : if (!CheckValidAndErrorOutIfNot())
1477 2 : return {};
1478 78 : std::vector<std::string> names;
1479 85 : for (const auto &iter : m_oMapMDArrays)
1480 46 : names.push_back(iter.first);
1481 39 : return names;
1482 : }
1483 :
1484 : /************************************************************************/
1485 : /* OpenMDArray() */
1486 : /************************************************************************/
1487 :
1488 167 : std::shared_ptr<GDALMDArray> MEMGroup::OpenMDArray(const std::string &osName,
1489 : CSLConstList) const
1490 : {
1491 167 : if (!CheckValidAndErrorOutIfNot())
1492 0 : return nullptr;
1493 167 : auto oIter = m_oMapMDArrays.find(osName);
1494 167 : if (oIter != m_oMapMDArrays.end())
1495 140 : return oIter->second;
1496 27 : return nullptr;
1497 : }
1498 :
1499 : /************************************************************************/
1500 : /* GetGroupNames() */
1501 : /************************************************************************/
1502 :
1503 58 : std::vector<std::string> MEMGroup::GetGroupNames(CSLConstList) const
1504 : {
1505 58 : if (!CheckValidAndErrorOutIfNot())
1506 0 : return {};
1507 116 : std::vector<std::string> names;
1508 96 : for (const auto &iter : m_oMapGroups)
1509 38 : names.push_back(iter.first);
1510 58 : return names;
1511 : }
1512 :
1513 : /************************************************************************/
1514 : /* OpenGroup() */
1515 : /************************************************************************/
1516 :
1517 58 : std::shared_ptr<GDALGroup> MEMGroup::OpenGroup(const std::string &osName,
1518 : CSLConstList) const
1519 : {
1520 58 : if (!CheckValidAndErrorOutIfNot())
1521 0 : return nullptr;
1522 58 : auto oIter = m_oMapGroups.find(osName);
1523 58 : if (oIter != m_oMapGroups.end())
1524 53 : return oIter->second;
1525 5 : return nullptr;
1526 : }
1527 :
1528 : /************************************************************************/
1529 : /* Create() */
1530 : /************************************************************************/
1531 :
1532 : /*static*/
1533 2760 : std::shared_ptr<MEMGroup> MEMGroup::Create(const std::string &osParentName,
1534 : const char *pszName)
1535 : {
1536 : auto newGroup(
1537 2760 : std::shared_ptr<MEMGroup>(new MEMGroup(osParentName, pszName)));
1538 2760 : newGroup->SetSelf(newGroup);
1539 2760 : if (osParentName.empty())
1540 148 : newGroup->m_poRootGroupWeak = newGroup;
1541 2760 : return newGroup;
1542 : }
1543 :
1544 : /************************************************************************/
1545 : /* CreateGroup() */
1546 : /************************************************************************/
1547 :
1548 27 : std::shared_ptr<GDALGroup> MEMGroup::CreateGroup(const std::string &osName,
1549 : CSLConstList /*papszOptions*/)
1550 : {
1551 27 : if (!CheckValidAndErrorOutIfNot())
1552 0 : return nullptr;
1553 27 : if (osName.empty())
1554 : {
1555 1 : CPLError(CE_Failure, CPLE_NotSupported,
1556 : "Empty group name not supported");
1557 1 : return nullptr;
1558 : }
1559 26 : if (m_oMapGroups.find(osName) != m_oMapGroups.end())
1560 : {
1561 0 : CPLError(CE_Failure, CPLE_AppDefined,
1562 : "A group with same name already exists");
1563 0 : return nullptr;
1564 : }
1565 52 : auto newGroup = MEMGroup::Create(GetFullName(), osName.c_str());
1566 26 : newGroup->m_pParent = std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock());
1567 26 : newGroup->m_poRootGroupWeak = m_poRootGroupWeak;
1568 26 : m_oMapGroups[osName] = newGroup;
1569 26 : return newGroup;
1570 : }
1571 :
1572 : /************************************************************************/
1573 : /* DeleteGroup() */
1574 : /************************************************************************/
1575 :
1576 2 : bool MEMGroup::DeleteGroup(const std::string &osName,
1577 : CSLConstList /*papszOptions*/)
1578 : {
1579 2 : if (!CheckValidAndErrorOutIfNot())
1580 0 : return false;
1581 2 : auto oIter = m_oMapGroups.find(osName);
1582 2 : if (oIter == m_oMapGroups.end())
1583 : {
1584 1 : CPLError(CE_Failure, CPLE_AppDefined,
1585 : "Group %s is not a sub-group of this group", osName.c_str());
1586 1 : return false;
1587 : }
1588 :
1589 1 : oIter->second->Deleted();
1590 1 : m_oMapGroups.erase(oIter);
1591 1 : return true;
1592 : }
1593 :
1594 : /************************************************************************/
1595 : /* NotifyChildrenOfDeletion() */
1596 : /************************************************************************/
1597 :
1598 16 : void MEMGroup::NotifyChildrenOfDeletion()
1599 : {
1600 17 : for (const auto &oIter : m_oMapGroups)
1601 1 : oIter.second->ParentDeleted();
1602 17 : for (const auto &oIter : m_oMapMDArrays)
1603 1 : oIter.second->ParentDeleted();
1604 37 : for (const auto &oIter : m_oMapAttributes)
1605 21 : oIter.second->ParentDeleted();
1606 16 : for (const auto &oIter : m_oMapDimensions)
1607 0 : oIter.second->ParentDeleted();
1608 16 : }
1609 :
1610 : /************************************************************************/
1611 : /* CreateMDArray() */
1612 : /************************************************************************/
1613 :
1614 210 : std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray(
1615 : const std::string &osName,
1616 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1617 : const GDALExtendedDataType &oType, void *pData, CSLConstList papszOptions)
1618 : {
1619 210 : if (!CheckValidAndErrorOutIfNot())
1620 0 : return nullptr;
1621 210 : if (osName.empty())
1622 : {
1623 1 : CPLError(CE_Failure, CPLE_NotSupported,
1624 : "Empty array name not supported");
1625 1 : return nullptr;
1626 : }
1627 209 : if (m_oMapMDArrays.find(osName) != m_oMapMDArrays.end())
1628 : {
1629 1 : CPLError(CE_Failure, CPLE_AppDefined,
1630 : "An array with same name already exists");
1631 1 : return nullptr;
1632 : }
1633 : auto newArray(
1634 416 : MEMMDArray::Create(GetFullName(), osName, aoDimensions, oType));
1635 :
1636 208 : GByte *pabyData = nullptr;
1637 416 : std::vector<GPtrDiff_t> anStrides;
1638 208 : if (pData)
1639 : {
1640 20 : pabyData = static_cast<GByte *>(pData);
1641 20 : const char *pszStrides = CSLFetchNameValue(papszOptions, "STRIDES");
1642 20 : if (pszStrides)
1643 : {
1644 20 : CPLStringList aosStrides(CSLTokenizeString2(pszStrides, ",", 0));
1645 20 : if (static_cast<size_t>(aosStrides.size()) != aoDimensions.size())
1646 : {
1647 0 : CPLError(CE_Failure, CPLE_AppDefined,
1648 : "Invalid number of strides");
1649 0 : return nullptr;
1650 : }
1651 60 : for (int i = 0; i < aosStrides.size(); i++)
1652 : {
1653 40 : const auto nStride = CPLAtoGIntBig(aosStrides[i]);
1654 40 : anStrides.push_back(static_cast<GPtrDiff_t>(nStride));
1655 : }
1656 : }
1657 : }
1658 208 : if (!newArray->Init(pabyData, anStrides))
1659 2 : return nullptr;
1660 :
1661 559 : for (auto &poDim : newArray->GetDimensions())
1662 : {
1663 706 : const auto dim = std::dynamic_pointer_cast<MEMDimension>(poDim);
1664 353 : if (dim)
1665 348 : dim->RegisterUsingArray(newArray.get());
1666 : }
1667 :
1668 206 : newArray->RegisterGroup(m_pSelf);
1669 206 : m_oMapMDArrays[osName] = newArray;
1670 206 : return newArray;
1671 : }
1672 :
1673 190 : std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray(
1674 : const std::string &osName,
1675 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1676 : const GDALExtendedDataType &oType, CSLConstList papszOptions)
1677 : {
1678 190 : void *pData = nullptr;
1679 190 : const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER");
1680 190 : if (pszDataPointer)
1681 : {
1682 : // Will not work on architectures with "capability pointers"
1683 0 : pData = CPLScanPointer(pszDataPointer,
1684 0 : static_cast<int>(strlen(pszDataPointer)));
1685 : }
1686 190 : return CreateMDArray(osName, aoDimensions, oType, pData, papszOptions);
1687 : }
1688 :
1689 : /************************************************************************/
1690 : /* DeleteMDArray() */
1691 : /************************************************************************/
1692 :
1693 2 : bool MEMGroup::DeleteMDArray(const std::string &osName,
1694 : CSLConstList /*papszOptions*/)
1695 : {
1696 2 : if (!CheckValidAndErrorOutIfNot())
1697 0 : return false;
1698 2 : auto oIter = m_oMapMDArrays.find(osName);
1699 2 : if (oIter == m_oMapMDArrays.end())
1700 : {
1701 1 : CPLError(CE_Failure, CPLE_AppDefined,
1702 : "Array %s is not an array of this group", osName.c_str());
1703 1 : return false;
1704 : }
1705 :
1706 1 : oIter->second->Deleted();
1707 1 : m_oMapMDArrays.erase(oIter);
1708 1 : return true;
1709 : }
1710 :
1711 : /************************************************************************/
1712 : /* MEMGroupCreateMDArray() */
1713 : /************************************************************************/
1714 :
1715 : // Used by NUMPYMultiDimensionalDataset
1716 20 : std::shared_ptr<GDALMDArray> MEMGroupCreateMDArray(
1717 : GDALGroup *poGroup, const std::string &osName,
1718 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1719 : const GDALExtendedDataType &oDataType, void *pData,
1720 : CSLConstList papszOptions)
1721 : {
1722 20 : auto poMemGroup = dynamic_cast<MEMGroup *>(poGroup);
1723 20 : if (!poMemGroup)
1724 : {
1725 0 : CPLError(CE_Failure, CPLE_AppDefined,
1726 : "MEMGroupCreateMDArray(): poGroup not of type MEMGroup");
1727 0 : return nullptr;
1728 : }
1729 : return poMemGroup->CreateMDArray(osName, aoDimensions, oDataType, pData,
1730 20 : papszOptions);
1731 : }
1732 :
1733 : /************************************************************************/
1734 : /* GetAttribute() */
1735 : /************************************************************************/
1736 :
1737 : std::shared_ptr<GDALAttribute>
1738 130 : MEMGroup::GetAttribute(const std::string &osName) const
1739 : {
1740 130 : if (!CheckValidAndErrorOutIfNot())
1741 3 : return nullptr;
1742 127 : auto oIter = m_oMapAttributes.find(osName);
1743 127 : if (oIter != m_oMapAttributes.end())
1744 112 : return oIter->second;
1745 15 : return nullptr;
1746 : }
1747 :
1748 : /************************************************************************/
1749 : /* GetAttributes() */
1750 : /************************************************************************/
1751 :
1752 : std::vector<std::shared_ptr<GDALAttribute>>
1753 5864 : MEMGroup::GetAttributes(CSLConstList) const
1754 : {
1755 5864 : if (!CheckValidAndErrorOutIfNot())
1756 6 : return {};
1757 11716 : std::vector<std::shared_ptr<GDALAttribute>> oRes;
1758 7284 : for (const auto &oIter : m_oMapAttributes)
1759 : {
1760 1426 : oRes.push_back(oIter.second);
1761 : }
1762 5858 : return oRes;
1763 : }
1764 :
1765 : /************************************************************************/
1766 : /* GetDimensions() */
1767 : /************************************************************************/
1768 :
1769 : std::vector<std::shared_ptr<GDALDimension>>
1770 50 : MEMGroup::GetDimensions(CSLConstList) const
1771 : {
1772 50 : if (!CheckValidAndErrorOutIfNot())
1773 0 : return {};
1774 100 : std::vector<std::shared_ptr<GDALDimension>> oRes;
1775 169 : for (const auto &oIter : m_oMapDimensions)
1776 : {
1777 119 : oRes.push_back(oIter.second);
1778 : }
1779 50 : return oRes;
1780 : }
1781 :
1782 : /************************************************************************/
1783 : /* CreateAttribute() */
1784 : /************************************************************************/
1785 :
1786 : std::shared_ptr<GDALAttribute>
1787 533 : MEMGroup::CreateAttribute(const std::string &osName,
1788 : const std::vector<GUInt64> &anDimensions,
1789 : const GDALExtendedDataType &oDataType, CSLConstList)
1790 : {
1791 533 : if (!CheckValidAndErrorOutIfNot())
1792 0 : return nullptr;
1793 533 : if (osName.empty())
1794 : {
1795 1 : CPLError(CE_Failure, CPLE_NotSupported,
1796 : "Empty attribute name not supported");
1797 1 : return nullptr;
1798 : }
1799 532 : if (m_oMapAttributes.find(osName) != m_oMapAttributes.end())
1800 : {
1801 0 : CPLError(CE_Failure, CPLE_AppDefined,
1802 : "An attribute with same name already exists");
1803 0 : return nullptr;
1804 : }
1805 : auto newAttr(MEMAttribute::Create(
1806 1064 : std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()), osName,
1807 1064 : anDimensions, oDataType));
1808 532 : if (!newAttr)
1809 0 : return nullptr;
1810 532 : m_oMapAttributes[osName] = newAttr;
1811 532 : return newAttr;
1812 : }
1813 :
1814 : /************************************************************************/
1815 : /* DeleteAttribute() */
1816 : /************************************************************************/
1817 :
1818 26 : bool MEMGroup::DeleteAttribute(const std::string &osName,
1819 : CSLConstList /*papszOptions*/)
1820 : {
1821 26 : if (!CheckValidAndErrorOutIfNot())
1822 0 : return false;
1823 26 : auto oIter = m_oMapAttributes.find(osName);
1824 26 : if (oIter == m_oMapAttributes.end())
1825 : {
1826 13 : CPLError(CE_Failure, CPLE_AppDefined,
1827 : "Attribute %s is not an attribute of this group",
1828 : osName.c_str());
1829 13 : return false;
1830 : }
1831 :
1832 13 : oIter->second->Deleted();
1833 13 : m_oMapAttributes.erase(oIter);
1834 13 : return true;
1835 : }
1836 :
1837 : /************************************************************************/
1838 : /* Rename() */
1839 : /************************************************************************/
1840 :
1841 4 : bool MEMGroup::Rename(const std::string &osNewName)
1842 : {
1843 4 : if (!CheckValidAndErrorOutIfNot())
1844 0 : return false;
1845 4 : if (osNewName.empty())
1846 : {
1847 1 : CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
1848 1 : return false;
1849 : }
1850 3 : if (m_osName == "/")
1851 : {
1852 1 : CPLError(CE_Failure, CPLE_NotSupported, "Cannot rename root group");
1853 1 : return false;
1854 : }
1855 4 : auto pParent = m_pParent.lock();
1856 2 : if (pParent)
1857 : {
1858 2 : if (pParent->m_oMapGroups.find(osNewName) !=
1859 4 : pParent->m_oMapGroups.end())
1860 : {
1861 1 : CPLError(CE_Failure, CPLE_AppDefined,
1862 : "A group with same name already exists");
1863 1 : return false;
1864 : }
1865 1 : pParent->m_oMapGroups.erase(pParent->m_oMapGroups.find(m_osName));
1866 : }
1867 :
1868 1 : BaseRename(osNewName);
1869 :
1870 1 : if (pParent)
1871 : {
1872 1 : CPLAssert(m_pSelf.lock());
1873 1 : pParent->m_oMapGroups[m_osName] = m_pSelf.lock();
1874 : }
1875 :
1876 1 : return true;
1877 : }
1878 :
1879 : /************************************************************************/
1880 : /* NotifyChildrenOfRenaming() */
1881 : /************************************************************************/
1882 :
1883 3 : void MEMGroup::NotifyChildrenOfRenaming()
1884 : {
1885 5 : for (const auto &oIter : m_oMapGroups)
1886 2 : oIter.second->ParentRenamed(m_osFullName);
1887 5 : for (const auto &oIter : m_oMapMDArrays)
1888 2 : oIter.second->ParentRenamed(m_osFullName);
1889 5 : for (const auto &oIter : m_oMapAttributes)
1890 2 : oIter.second->ParentRenamed(m_osFullName);
1891 4 : for (const auto &oIter : m_oMapDimensions)
1892 1 : oIter.second->ParentRenamed(m_osFullName);
1893 3 : }
1894 :
1895 : /************************************************************************/
1896 : /* RenameDimension() */
1897 : /************************************************************************/
1898 :
1899 2 : bool MEMGroup::RenameDimension(const std::string &osOldName,
1900 : const std::string &osNewName)
1901 : {
1902 2 : if (m_oMapDimensions.find(osNewName) != m_oMapDimensions.end())
1903 : {
1904 1 : CPLError(CE_Failure, CPLE_AppDefined,
1905 : "A dimension with same name already exists");
1906 1 : return false;
1907 : }
1908 1 : auto oIter = m_oMapDimensions.find(osOldName);
1909 1 : if (oIter == m_oMapDimensions.end())
1910 : {
1911 0 : CPLAssert(false);
1912 : return false;
1913 : }
1914 1 : auto poDim = std::move(oIter->second);
1915 1 : m_oMapDimensions.erase(oIter);
1916 1 : m_oMapDimensions[osNewName] = std::move(poDim);
1917 1 : return true;
1918 : }
1919 :
1920 : /************************************************************************/
1921 : /* RenameArray() */
1922 : /************************************************************************/
1923 :
1924 2 : bool MEMGroup::RenameArray(const std::string &osOldName,
1925 : const std::string &osNewName)
1926 : {
1927 2 : if (m_oMapMDArrays.find(osNewName) != m_oMapMDArrays.end())
1928 : {
1929 1 : CPLError(CE_Failure, CPLE_AppDefined,
1930 : "An array with same name already exists");
1931 1 : return false;
1932 : }
1933 1 : auto oIter = m_oMapMDArrays.find(osOldName);
1934 1 : if (oIter == m_oMapMDArrays.end())
1935 : {
1936 0 : CPLAssert(false);
1937 : return false;
1938 : }
1939 1 : auto poArray = std::move(oIter->second);
1940 1 : m_oMapMDArrays.erase(oIter);
1941 1 : m_oMapMDArrays[osNewName] = std::move(poArray);
1942 1 : return true;
1943 : }
1944 :
1945 : /************************************************************************/
1946 : /* MEMAbstractMDArray() */
1947 : /************************************************************************/
1948 :
1949 877 : MEMAbstractMDArray::MEMAbstractMDArray(
1950 : const std::string &osParentName, const std::string &osName,
1951 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1952 0 : const GDALExtendedDataType &oType)
1953 : : GDALAbstractMDArray(osParentName, osName), m_aoDims(aoDimensions),
1954 877 : m_oType(oType)
1955 : {
1956 877 : }
1957 :
1958 : /************************************************************************/
1959 : /* ~MEMAbstractMDArray() */
1960 : /************************************************************************/
1961 :
1962 877 : MEMAbstractMDArray::~MEMAbstractMDArray()
1963 : {
1964 877 : FreeArray();
1965 877 : }
1966 :
1967 : /************************************************************************/
1968 : /* FreeArray() */
1969 : /************************************************************************/
1970 :
1971 883 : void MEMAbstractMDArray::FreeArray()
1972 : {
1973 883 : if (m_bOwnArray)
1974 : {
1975 846 : if (m_oType.NeedsFreeDynamicMemory())
1976 : {
1977 438 : GByte *pabyPtr = m_pabyArray;
1978 438 : GByte *pabyEnd = m_pabyArray + m_nTotalSize;
1979 438 : const auto nDTSize(m_oType.GetSize());
1980 930 : while (pabyPtr < pabyEnd)
1981 : {
1982 492 : m_oType.FreeDynamicMemory(pabyPtr);
1983 492 : pabyPtr += nDTSize;
1984 : }
1985 : }
1986 846 : VSIFree(m_pabyArray);
1987 846 : m_pabyArray = nullptr;
1988 846 : m_nTotalSize = 0;
1989 846 : m_bOwnArray = false;
1990 : }
1991 883 : }
1992 :
1993 : /************************************************************************/
1994 : /* Init() */
1995 : /************************************************************************/
1996 :
1997 877 : bool MEMAbstractMDArray::Init(GByte *pData,
1998 : const std::vector<GPtrDiff_t> &anStrides)
1999 : {
2000 877 : GUInt64 nTotalSize = m_oType.GetSize();
2001 877 : if (!m_aoDims.empty())
2002 : {
2003 318 : if (anStrides.empty())
2004 : {
2005 298 : m_anStrides.resize(m_aoDims.size());
2006 : }
2007 : else
2008 : {
2009 20 : CPLAssert(anStrides.size() == m_aoDims.size());
2010 20 : m_anStrides = anStrides;
2011 : }
2012 :
2013 : // To compute strides we must proceed from the fastest varying dimension
2014 : // (the last one), and then reverse the result
2015 827 : for (size_t i = m_aoDims.size(); i != 0;)
2016 : {
2017 512 : --i;
2018 512 : const auto &poDim = m_aoDims[i];
2019 512 : auto nDimSize = poDim->GetSize();
2020 512 : if (nDimSize == 0)
2021 : {
2022 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2023 : "Illegal dimension size 0");
2024 0 : return false;
2025 : }
2026 512 : if (nTotalSize > std::numeric_limits<GUInt64>::max() / nDimSize)
2027 : {
2028 3 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
2029 3 : return false;
2030 : }
2031 509 : auto nNewSize = nTotalSize * nDimSize;
2032 509 : if (anStrides.empty())
2033 469 : m_anStrides[i] = static_cast<size_t>(nTotalSize);
2034 509 : nTotalSize = nNewSize;
2035 : }
2036 : }
2037 :
2038 : // We restrict the size of the allocation so that all elements can be
2039 : // indexed by GPtrDiff_t
2040 874 : if (nTotalSize >
2041 874 : static_cast<size_t>(std::numeric_limits<GPtrDiff_t>::max()))
2042 : {
2043 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
2044 1 : return false;
2045 : }
2046 873 : m_nTotalSize = static_cast<size_t>(nTotalSize);
2047 873 : if (pData)
2048 : {
2049 27 : m_pabyArray = pData;
2050 : }
2051 : else
2052 : {
2053 846 : m_pabyArray = static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, m_nTotalSize));
2054 846 : m_bOwnArray = true;
2055 : }
2056 :
2057 873 : return m_pabyArray != nullptr;
2058 : }
2059 :
2060 : /************************************************************************/
2061 : /* FastCopy() */
2062 : /************************************************************************/
2063 :
2064 : template <int N>
2065 211 : inline static void FastCopy(size_t nIters, GByte *dstPtr, const GByte *srcPtr,
2066 : GPtrDiff_t dst_inc_offset,
2067 : GPtrDiff_t src_inc_offset)
2068 : {
2069 211 : if (nIters >= 8)
2070 : {
2071 : #define COPY_ELT(i) \
2072 : memcpy(dstPtr + (i)*dst_inc_offset, srcPtr + (i)*src_inc_offset, N)
2073 : while (true)
2074 : {
2075 43 : COPY_ELT(0);
2076 43 : COPY_ELT(1);
2077 43 : COPY_ELT(2);
2078 43 : COPY_ELT(3);
2079 43 : COPY_ELT(4);
2080 43 : COPY_ELT(5);
2081 43 : COPY_ELT(6);
2082 43 : COPY_ELT(7);
2083 43 : nIters -= 8;
2084 43 : srcPtr += 8 * src_inc_offset;
2085 43 : dstPtr += 8 * dst_inc_offset;
2086 43 : if (nIters < 8)
2087 21 : break;
2088 : }
2089 21 : if (nIters == 0)
2090 0 : return;
2091 : }
2092 : while (true)
2093 : {
2094 418 : memcpy(dstPtr, srcPtr, N);
2095 418 : if ((--nIters) == 0)
2096 211 : break;
2097 207 : srcPtr += src_inc_offset;
2098 207 : dstPtr += dst_inc_offset;
2099 : }
2100 : }
2101 :
2102 : /************************************************************************/
2103 : /* ReadWrite() */
2104 : /************************************************************************/
2105 :
2106 914 : void MEMAbstractMDArray::ReadWrite(bool bIsWrite, const size_t *count,
2107 : std::vector<StackReadWrite> &stack,
2108 : const GDALExtendedDataType &srcType,
2109 : const GDALExtendedDataType &dstType) const
2110 : {
2111 914 : const auto nDims = m_aoDims.size();
2112 914 : const auto nDimsMinus1 = nDims - 1;
2113 1733 : const bool bBothAreNumericDT = srcType.GetClass() == GEDTC_NUMERIC &&
2114 819 : dstType.GetClass() == GEDTC_NUMERIC;
2115 : const bool bSameNumericDT =
2116 1727 : bBothAreNumericDT &&
2117 813 : srcType.GetNumericDataType() == dstType.GetNumericDataType();
2118 914 : const auto nSameDTSize = bSameNumericDT ? srcType.GetSize() : 0;
2119 : const bool bCanUseMemcpyLastDim =
2120 1592 : bSameNumericDT &&
2121 678 : stack[nDimsMinus1].src_inc_offset ==
2122 2162 : static_cast<GPtrDiff_t>(nSameDTSize) &&
2123 570 : stack[nDimsMinus1].dst_inc_offset ==
2124 570 : static_cast<GPtrDiff_t>(nSameDTSize);
2125 914 : const size_t nCopySizeLastDim =
2126 914 : bCanUseMemcpyLastDim ? nSameDTSize * count[nDimsMinus1] : 0;
2127 : const bool bNeedsFreeDynamicMemory =
2128 914 : bIsWrite && dstType.NeedsFreeDynamicMemory();
2129 :
2130 75986 : auto lambdaLastDim = [&](size_t idxPtr)
2131 : {
2132 75986 : auto srcPtr = stack[idxPtr].src_ptr;
2133 75986 : auto dstPtr = stack[idxPtr].dst_ptr;
2134 75986 : if (nCopySizeLastDim)
2135 : {
2136 75516 : memcpy(dstPtr, srcPtr, nCopySizeLastDim);
2137 : }
2138 : else
2139 : {
2140 940 : size_t nIters = count[nDimsMinus1];
2141 470 : const auto dst_inc_offset = stack[nDimsMinus1].dst_inc_offset;
2142 470 : const auto src_inc_offset = stack[nDimsMinus1].src_inc_offset;
2143 470 : if (bSameNumericDT)
2144 : {
2145 211 : if (nSameDTSize == 1)
2146 : {
2147 72 : FastCopy<1>(nIters, dstPtr, srcPtr, dst_inc_offset,
2148 : src_inc_offset);
2149 72 : return;
2150 : }
2151 139 : if (nSameDTSize == 2)
2152 : {
2153 46 : FastCopy<2>(nIters, dstPtr, srcPtr, dst_inc_offset,
2154 : src_inc_offset);
2155 46 : return;
2156 : }
2157 93 : if (nSameDTSize == 4)
2158 : {
2159 26 : FastCopy<4>(nIters, dstPtr, srcPtr, dst_inc_offset,
2160 : src_inc_offset);
2161 26 : return;
2162 : }
2163 67 : if (nSameDTSize == 8)
2164 : {
2165 65 : FastCopy<8>(nIters, dstPtr, srcPtr, dst_inc_offset,
2166 : src_inc_offset);
2167 65 : return;
2168 : }
2169 2 : if (nSameDTSize == 16)
2170 : {
2171 2 : FastCopy<16>(nIters, dstPtr, srcPtr, dst_inc_offset,
2172 : src_inc_offset);
2173 2 : return;
2174 : }
2175 0 : CPLAssert(false);
2176 : }
2177 518 : else if (bBothAreNumericDT
2178 : #if SIZEOF_VOIDP >= 8
2179 414 : && src_inc_offset <= std::numeric_limits<int>::max() &&
2180 155 : dst_inc_offset <= std::numeric_limits<int>::max()
2181 : #endif
2182 : )
2183 : {
2184 155 : GDALCopyWords64(srcPtr, srcType.GetNumericDataType(),
2185 : static_cast<int>(src_inc_offset), dstPtr,
2186 155 : dstType.GetNumericDataType(),
2187 : static_cast<int>(dst_inc_offset),
2188 : static_cast<GPtrDiff_t>(nIters));
2189 155 : return;
2190 : }
2191 :
2192 : while (true)
2193 : {
2194 189 : if (bNeedsFreeDynamicMemory)
2195 : {
2196 71 : dstType.FreeDynamicMemory(dstPtr);
2197 : }
2198 189 : GDALExtendedDataType::CopyValue(srcPtr, srcType, dstPtr,
2199 : dstType);
2200 189 : if ((--nIters) == 0)
2201 104 : break;
2202 85 : srcPtr += src_inc_offset;
2203 85 : dstPtr += dst_inc_offset;
2204 : }
2205 : }
2206 914 : };
2207 :
2208 914 : if (nDims == 1)
2209 : {
2210 595 : lambdaLastDim(0);
2211 : }
2212 319 : else if (nDims == 2)
2213 : {
2214 122 : auto nIters = count[0];
2215 : while (true)
2216 : {
2217 344 : lambdaLastDim(0);
2218 344 : if ((--nIters) == 0)
2219 122 : break;
2220 222 : stack[0].src_ptr += stack[0].src_inc_offset;
2221 222 : stack[0].dst_ptr += stack[0].dst_inc_offset;
2222 : }
2223 : }
2224 197 : else if (nDims == 3)
2225 : {
2226 150 : stack[0].nIters = count[0];
2227 : while (true)
2228 : {
2229 245 : stack[1].src_ptr = stack[0].src_ptr;
2230 245 : stack[1].dst_ptr = stack[0].dst_ptr;
2231 245 : auto nIters = count[1];
2232 : while (true)
2233 : {
2234 1843 : lambdaLastDim(1);
2235 1843 : if ((--nIters) == 0)
2236 245 : break;
2237 1598 : stack[1].src_ptr += stack[1].src_inc_offset;
2238 1598 : stack[1].dst_ptr += stack[1].dst_inc_offset;
2239 : }
2240 245 : if ((--stack[0].nIters) == 0)
2241 150 : break;
2242 95 : stack[0].src_ptr += stack[0].src_inc_offset;
2243 95 : stack[0].dst_ptr += stack[0].dst_inc_offset;
2244 95 : }
2245 : }
2246 : else
2247 : {
2248 : // Implementation valid for nDims >= 3
2249 :
2250 47 : size_t dimIdx = 0;
2251 : // Non-recursive implementation. Hence the gotos
2252 : // It might be possible to rewrite this without gotos, but I find they
2253 : // make it clearer to understand the recursive nature of the code
2254 149996 : lbl_next_depth:
2255 149996 : if (dimIdx == nDimsMinus1 - 1)
2256 : {
2257 51566 : auto nIters = count[dimIdx];
2258 : while (true)
2259 : {
2260 73204 : lambdaLastDim(dimIdx);
2261 73204 : if ((--nIters) == 0)
2262 51566 : break;
2263 21638 : stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
2264 21638 : stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
2265 : }
2266 : // If there was a test if( dimIdx > 0 ), that would be valid for
2267 : // nDims == 2
2268 51566 : goto lbl_return_to_caller;
2269 : }
2270 : else
2271 : {
2272 98430 : stack[dimIdx].nIters = count[dimIdx];
2273 : while (true)
2274 : {
2275 149949 : dimIdx++;
2276 149949 : stack[dimIdx].src_ptr = stack[dimIdx - 1].src_ptr;
2277 149949 : stack[dimIdx].dst_ptr = stack[dimIdx - 1].dst_ptr;
2278 149949 : goto lbl_next_depth;
2279 149949 : lbl_return_to_caller:
2280 149949 : dimIdx--;
2281 149949 : if ((--stack[dimIdx].nIters) == 0)
2282 98430 : break;
2283 51519 : stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
2284 51519 : stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
2285 : }
2286 98430 : if (dimIdx > 0)
2287 98383 : goto lbl_return_to_caller;
2288 : }
2289 : }
2290 914 : }
2291 :
2292 : /************************************************************************/
2293 : /* IRead() */
2294 : /************************************************************************/
2295 :
2296 963 : bool MEMAbstractMDArray::IRead(const GUInt64 *arrayStartIdx,
2297 : const size_t *count, const GInt64 *arrayStep,
2298 : const GPtrDiff_t *bufferStride,
2299 : const GDALExtendedDataType &bufferDataType,
2300 : void *pDstBuffer) const
2301 : {
2302 963 : if (!CheckValidAndErrorOutIfNot())
2303 0 : return false;
2304 :
2305 963 : const auto nDims = m_aoDims.size();
2306 963 : if (nDims == 0)
2307 : {
2308 403 : GDALExtendedDataType::CopyValue(m_pabyArray, m_oType, pDstBuffer,
2309 : bufferDataType);
2310 403 : return true;
2311 : }
2312 560 : std::vector<StackReadWrite> stack(nDims);
2313 560 : const auto nBufferDTSize = bufferDataType.GetSize();
2314 560 : GPtrDiff_t startSrcOffset = 0;
2315 1558 : for (size_t i = 0; i < nDims; i++)
2316 : {
2317 998 : startSrcOffset +=
2318 998 : static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]);
2319 1996 : stack[i].src_inc_offset =
2320 998 : static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]);
2321 998 : stack[i].dst_inc_offset =
2322 998 : static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize);
2323 : }
2324 560 : stack[0].src_ptr = m_pabyArray + startSrcOffset;
2325 560 : stack[0].dst_ptr = static_cast<GByte *>(pDstBuffer);
2326 :
2327 560 : ReadWrite(false, count, stack, m_oType, bufferDataType);
2328 560 : return true;
2329 : }
2330 :
2331 : /************************************************************************/
2332 : /* IWrite() */
2333 : /************************************************************************/
2334 :
2335 893 : bool MEMAbstractMDArray::IWrite(const GUInt64 *arrayStartIdx,
2336 : const size_t *count, const GInt64 *arrayStep,
2337 : const GPtrDiff_t *bufferStride,
2338 : const GDALExtendedDataType &bufferDataType,
2339 : const void *pSrcBuffer)
2340 : {
2341 893 : if (!CheckValidAndErrorOutIfNot())
2342 12 : return false;
2343 881 : if (!m_bWritable)
2344 : {
2345 2 : CPLError(CE_Failure, CPLE_AppDefined, "Non updatable object");
2346 2 : return false;
2347 : }
2348 :
2349 879 : m_bModified = true;
2350 :
2351 879 : const auto nDims = m_aoDims.size();
2352 879 : if (nDims == 0)
2353 : {
2354 525 : m_oType.FreeDynamicMemory(m_pabyArray);
2355 525 : GDALExtendedDataType::CopyValue(pSrcBuffer, bufferDataType, m_pabyArray,
2356 525 : m_oType);
2357 525 : return true;
2358 : }
2359 354 : std::vector<StackReadWrite> stack(nDims);
2360 354 : const auto nBufferDTSize = bufferDataType.GetSize();
2361 354 : GPtrDiff_t startDstOffset = 0;
2362 887 : for (size_t i = 0; i < nDims; i++)
2363 : {
2364 533 : startDstOffset +=
2365 533 : static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]);
2366 1066 : stack[i].dst_inc_offset =
2367 533 : static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]);
2368 533 : stack[i].src_inc_offset =
2369 533 : static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize);
2370 : }
2371 :
2372 354 : stack[0].dst_ptr = m_pabyArray + startDstOffset;
2373 354 : stack[0].src_ptr = static_cast<const GByte *>(pSrcBuffer);
2374 :
2375 354 : ReadWrite(true, count, stack, bufferDataType, m_oType);
2376 354 : return true;
2377 : }
2378 :
2379 : /************************************************************************/
2380 : /* MEMMDArray() */
2381 : /************************************************************************/
2382 :
2383 227 : MEMMDArray::MEMMDArray(
2384 : const std::string &osParentName, const std::string &osName,
2385 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
2386 227 : const GDALExtendedDataType &oType)
2387 : : GDALAbstractMDArray(osParentName, osName),
2388 : MEMAbstractMDArray(osParentName, osName, aoDimensions, oType),
2389 227 : GDALMDArray(osParentName, osName)
2390 : {
2391 227 : }
2392 :
2393 : /************************************************************************/
2394 : /* ~MEMMDArray() */
2395 : /************************************************************************/
2396 :
2397 454 : MEMMDArray::~MEMMDArray()
2398 : {
2399 227 : if (m_pabyNoData)
2400 : {
2401 37 : m_oType.FreeDynamicMemory(&m_pabyNoData[0]);
2402 37 : CPLFree(m_pabyNoData);
2403 : }
2404 :
2405 621 : for (auto &poDim : GetDimensions())
2406 : {
2407 788 : const auto dim = std::dynamic_pointer_cast<MEMDimension>(poDim);
2408 394 : if (dim)
2409 374 : dim->UnRegisterUsingArray(this);
2410 : }
2411 454 : }
2412 :
2413 : /************************************************************************/
2414 : /* GetRawNoDataValue() */
2415 : /************************************************************************/
2416 :
2417 192 : const void *MEMMDArray::GetRawNoDataValue() const
2418 : {
2419 192 : return m_pabyNoData;
2420 : }
2421 :
2422 : /************************************************************************/
2423 : /* SetRawNoDataValue() */
2424 : /************************************************************************/
2425 :
2426 42 : bool MEMMDArray::SetRawNoDataValue(const void *pNoData)
2427 : {
2428 42 : if (!CheckValidAndErrorOutIfNot())
2429 0 : return false;
2430 42 : if (m_pabyNoData)
2431 : {
2432 4 : m_oType.FreeDynamicMemory(&m_pabyNoData[0]);
2433 : }
2434 :
2435 42 : if (pNoData == nullptr)
2436 : {
2437 1 : CPLFree(m_pabyNoData);
2438 1 : m_pabyNoData = nullptr;
2439 : }
2440 : else
2441 : {
2442 41 : const auto nSize = m_oType.GetSize();
2443 41 : if (m_pabyNoData == nullptr)
2444 : {
2445 38 : m_pabyNoData = static_cast<GByte *>(CPLMalloc(nSize));
2446 : }
2447 41 : memset(m_pabyNoData, 0, nSize);
2448 41 : GDALExtendedDataType::CopyValue(pNoData, m_oType, m_pabyNoData,
2449 41 : m_oType);
2450 : }
2451 42 : return true;
2452 : }
2453 :
2454 : /************************************************************************/
2455 : /* GetAttribute() */
2456 : /************************************************************************/
2457 :
2458 : std::shared_ptr<GDALAttribute>
2459 259 : MEMMDArray::GetAttribute(const std::string &osName) const
2460 : {
2461 259 : if (!CheckValidAndErrorOutIfNot())
2462 0 : return nullptr;
2463 259 : auto oIter = m_oMapAttributes.find(osName);
2464 259 : if (oIter != m_oMapAttributes.end())
2465 54 : return oIter->second;
2466 205 : return nullptr;
2467 : }
2468 :
2469 : /************************************************************************/
2470 : /* GetAttributes() */
2471 : /************************************************************************/
2472 :
2473 : std::vector<std::shared_ptr<GDALAttribute>>
2474 54 : MEMMDArray::GetAttributes(CSLConstList) const
2475 : {
2476 54 : if (!CheckValidAndErrorOutIfNot())
2477 2 : return {};
2478 104 : std::vector<std::shared_ptr<GDALAttribute>> oRes;
2479 76 : for (const auto &oIter : m_oMapAttributes)
2480 : {
2481 24 : oRes.push_back(oIter.second);
2482 : }
2483 52 : return oRes;
2484 : }
2485 :
2486 : /************************************************************************/
2487 : /* CreateAttribute() */
2488 : /************************************************************************/
2489 :
2490 : std::shared_ptr<GDALAttribute>
2491 46 : MEMMDArray::CreateAttribute(const std::string &osName,
2492 : const std::vector<GUInt64> &anDimensions,
2493 : const GDALExtendedDataType &oDataType, CSLConstList)
2494 : {
2495 46 : if (!CheckValidAndErrorOutIfNot())
2496 0 : return nullptr;
2497 46 : if (osName.empty())
2498 : {
2499 1 : CPLError(CE_Failure, CPLE_NotSupported,
2500 : "Empty attribute name not supported");
2501 1 : return nullptr;
2502 : }
2503 45 : if (m_oMapAttributes.find(osName) != m_oMapAttributes.end())
2504 : {
2505 0 : CPLError(CE_Failure, CPLE_AppDefined,
2506 : "An attribute with same name already exists");
2507 0 : return nullptr;
2508 : }
2509 90 : auto poSelf = std::dynamic_pointer_cast<MEMMDArray>(m_pSelf.lock());
2510 45 : CPLAssert(poSelf);
2511 90 : auto newAttr(MEMAttribute::Create(poSelf, osName, anDimensions, oDataType));
2512 45 : if (!newAttr)
2513 0 : return nullptr;
2514 45 : m_oMapAttributes[osName] = newAttr;
2515 45 : return newAttr;
2516 : }
2517 :
2518 : /************************************************************************/
2519 : /* DeleteAttribute() */
2520 : /************************************************************************/
2521 :
2522 4 : bool MEMMDArray::DeleteAttribute(const std::string &osName,
2523 : CSLConstList /*papszOptions*/)
2524 : {
2525 4 : if (!CheckValidAndErrorOutIfNot())
2526 0 : return false;
2527 4 : auto oIter = m_oMapAttributes.find(osName);
2528 4 : if (oIter == m_oMapAttributes.end())
2529 : {
2530 1 : CPLError(CE_Failure, CPLE_AppDefined,
2531 : "Attribute %s is not an attribute of this array",
2532 : osName.c_str());
2533 1 : return false;
2534 : }
2535 :
2536 3 : oIter->second->Deleted();
2537 3 : m_oMapAttributes.erase(oIter);
2538 3 : return true;
2539 : }
2540 :
2541 : /************************************************************************/
2542 : /* GetCoordinateVariables() */
2543 : /************************************************************************/
2544 :
2545 : std::vector<std::shared_ptr<GDALMDArray>>
2546 15 : MEMMDArray::GetCoordinateVariables() const
2547 : {
2548 15 : if (!CheckValidAndErrorOutIfNot())
2549 0 : return {};
2550 30 : std::vector<std::shared_ptr<GDALMDArray>> ret;
2551 45 : const auto poCoordinates = GetAttribute("coordinates");
2552 9 : if (poCoordinates &&
2553 24 : poCoordinates->GetDataType().GetClass() == GEDTC_STRING &&
2554 9 : poCoordinates->GetDimensionCount() == 0)
2555 : {
2556 9 : const char *pszCoordinates = poCoordinates->ReadAsString();
2557 9 : if (pszCoordinates)
2558 : {
2559 18 : auto poGroup = m_poGroupWeak.lock();
2560 9 : if (!poGroup)
2561 : {
2562 0 : CPLError(CE_Failure, CPLE_AppDefined,
2563 : "Cannot access coordinate variables of %s has "
2564 : "belonging group has gone out of scope",
2565 0 : GetName().c_str());
2566 : }
2567 : else
2568 : {
2569 : const CPLStringList aosNames(
2570 18 : CSLTokenizeString2(pszCoordinates, " ", 0));
2571 35 : for (int i = 0; i < aosNames.size(); i++)
2572 : {
2573 78 : auto poCoordinateVar = poGroup->OpenMDArray(aosNames[i]);
2574 26 : if (poCoordinateVar)
2575 : {
2576 25 : ret.emplace_back(poCoordinateVar);
2577 : }
2578 : else
2579 : {
2580 1 : CPLError(CE_Warning, CPLE_AppDefined,
2581 : "Cannot find variable corresponding to "
2582 : "coordinate %s",
2583 : aosNames[i]);
2584 : }
2585 : }
2586 : }
2587 : }
2588 : }
2589 :
2590 15 : return ret;
2591 : }
2592 :
2593 : /************************************************************************/
2594 : /* Resize() */
2595 : /************************************************************************/
2596 :
2597 17 : bool MEMMDArray::Resize(const std::vector<GUInt64> &anNewDimSizes,
2598 : CSLConstList /* papszOptions */)
2599 : {
2600 17 : return Resize(anNewDimSizes, /*bResizeOtherArrays=*/true);
2601 : }
2602 :
2603 21 : bool MEMMDArray::Resize(const std::vector<GUInt64> &anNewDimSizes,
2604 : bool bResizeOtherArrays)
2605 : {
2606 21 : if (!CheckValidAndErrorOutIfNot())
2607 0 : return false;
2608 21 : if (!IsWritable())
2609 : {
2610 0 : CPLError(CE_Failure, CPLE_AppDefined,
2611 : "Resize() not supported on read-only file");
2612 0 : return false;
2613 : }
2614 21 : if (!m_bOwnArray)
2615 : {
2616 0 : CPLError(
2617 : CE_Failure, CPLE_AppDefined,
2618 : "Resize() not supported on an array that does not own its memory");
2619 0 : return false;
2620 : }
2621 :
2622 21 : const auto nDimCount = GetDimensionCount();
2623 21 : if (anNewDimSizes.size() != nDimCount)
2624 : {
2625 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2626 : "Not expected number of values in anNewDimSizes.");
2627 0 : return false;
2628 : }
2629 :
2630 21 : auto &dims = GetDimensions();
2631 42 : std::vector<size_t> anDecreasedDimIdx;
2632 42 : std::vector<size_t> anGrownDimIdx;
2633 42 : std::map<GDALDimension *, GUInt64> oMapDimToSize;
2634 61 : for (size_t i = 0; i < nDimCount; ++i)
2635 : {
2636 43 : auto oIter = oMapDimToSize.find(dims[i].get());
2637 43 : if (oIter != oMapDimToSize.end() && oIter->second != anNewDimSizes[i])
2638 : {
2639 2 : CPLError(CE_Failure, CPLE_AppDefined,
2640 : "Cannot resize a dimension referenced several times "
2641 : "to different sizes");
2642 3 : return false;
2643 : }
2644 41 : if (anNewDimSizes[i] != dims[i]->GetSize())
2645 : {
2646 22 : if (anNewDimSizes[i] == 0)
2647 : {
2648 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2649 : "Illegal dimension size 0");
2650 1 : return false;
2651 : }
2652 21 : auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
2653 21 : if (!dim)
2654 : {
2655 0 : CPLError(
2656 : CE_Failure, CPLE_AppDefined,
2657 : "Cannot resize a dimension that is not a MEMDimension");
2658 0 : return false;
2659 : }
2660 21 : oMapDimToSize[dim.get()] = anNewDimSizes[i];
2661 21 : if (anNewDimSizes[i] < dims[i]->GetSize())
2662 : {
2663 7 : anDecreasedDimIdx.push_back(i);
2664 : }
2665 : else
2666 : {
2667 14 : anGrownDimIdx.push_back(i);
2668 : }
2669 : }
2670 : else
2671 : {
2672 19 : oMapDimToSize[dims[i].get()] = dims[i]->GetSize();
2673 : }
2674 : }
2675 :
2676 132 : const auto ResizeOtherArrays = [this, &anNewDimSizes, nDimCount, &dims]()
2677 : {
2678 20 : std::set<MEMMDArray *> oSetArrays;
2679 10 : std::map<GDALDimension *, GUInt64> oMapNewSize;
2680 30 : for (size_t i = 0; i < nDimCount; ++i)
2681 : {
2682 20 : if (anNewDimSizes[i] != dims[i]->GetSize())
2683 : {
2684 24 : auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
2685 12 : if (!dim)
2686 : {
2687 0 : CPLAssert(false);
2688 : }
2689 : else
2690 : {
2691 12 : oMapNewSize[dims[i].get()] = anNewDimSizes[i];
2692 28 : for (const auto &poArray : dim->GetUsingArrays())
2693 : {
2694 16 : if (poArray != this)
2695 4 : oSetArrays.insert(poArray);
2696 : }
2697 : }
2698 : }
2699 : }
2700 :
2701 10 : bool bOK = true;
2702 14 : for (auto *poArray : oSetArrays)
2703 : {
2704 4 : const auto &apoOtherDims = poArray->GetDimensions();
2705 : std::vector<GUInt64> anOtherArrayNewDimSizes(
2706 4 : poArray->GetDimensionCount());
2707 14 : for (size_t i = 0; i < anOtherArrayNewDimSizes.size(); ++i)
2708 : {
2709 10 : auto oIter = oMapNewSize.find(apoOtherDims[i].get());
2710 10 : if (oIter != oMapNewSize.end())
2711 4 : anOtherArrayNewDimSizes[i] = oIter->second;
2712 : else
2713 6 : anOtherArrayNewDimSizes[i] = apoOtherDims[i]->GetSize();
2714 : }
2715 4 : if (!poArray->Resize(anOtherArrayNewDimSizes,
2716 : /*bResizeOtherArrays=*/false))
2717 : {
2718 0 : bOK = false;
2719 0 : break;
2720 : }
2721 : }
2722 10 : if (!bOK)
2723 : {
2724 0 : CPLError(CE_Failure, CPLE_AppDefined,
2725 : "Resizing of another array referencing the same dimension "
2726 : "as one modified on the current array failed. All arrays "
2727 : "referencing that dimension will be invalidated.");
2728 0 : Invalidate();
2729 0 : for (auto *poArray : oSetArrays)
2730 : {
2731 0 : poArray->Invalidate();
2732 : }
2733 : }
2734 :
2735 20 : return bOK;
2736 18 : };
2737 :
2738 : // Decrease slowest varying dimension
2739 24 : if (anGrownDimIdx.empty() && anDecreasedDimIdx.size() == 1 &&
2740 6 : anDecreasedDimIdx[0] == 0)
2741 : {
2742 4 : CPLAssert(m_nTotalSize % dims[0]->GetSize() == 0);
2743 4 : const size_t nNewTotalSize = static_cast<size_t>(
2744 4 : (m_nTotalSize / dims[0]->GetSize()) * anNewDimSizes[0]);
2745 4 : if (m_oType.NeedsFreeDynamicMemory())
2746 : {
2747 0 : GByte *pabyPtr = m_pabyArray + nNewTotalSize;
2748 0 : GByte *pabyEnd = m_pabyArray + m_nTotalSize;
2749 0 : const auto nDTSize(m_oType.GetSize());
2750 0 : while (pabyPtr < pabyEnd)
2751 : {
2752 0 : m_oType.FreeDynamicMemory(pabyPtr);
2753 0 : pabyPtr += nDTSize;
2754 : }
2755 : }
2756 : // shrinking... cannot fail, and even if it does, that's ok
2757 : GByte *pabyArray = static_cast<GByte *>(
2758 4 : VSI_REALLOC_VERBOSE(m_pabyArray, nNewTotalSize));
2759 4 : if (pabyArray)
2760 4 : m_pabyArray = pabyArray;
2761 4 : m_nTotalSize = nNewTotalSize;
2762 :
2763 4 : if (bResizeOtherArrays)
2764 : {
2765 3 : if (!ResizeOtherArrays())
2766 0 : return false;
2767 :
2768 6 : auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[0]);
2769 3 : if (dim)
2770 : {
2771 3 : dim->SetSize(anNewDimSizes[0]);
2772 : }
2773 : else
2774 : {
2775 0 : CPLAssert(false);
2776 : }
2777 : }
2778 4 : return true;
2779 : }
2780 :
2781 : // Increase slowest varying dimension
2782 24 : if (anDecreasedDimIdx.empty() && anGrownDimIdx.size() == 1 &&
2783 10 : anGrownDimIdx[0] == 0)
2784 : {
2785 6 : CPLAssert(m_nTotalSize % dims[0]->GetSize() == 0);
2786 6 : GUInt64 nNewTotalSize64 = m_nTotalSize / dims[0]->GetSize();
2787 6 : if (nNewTotalSize64 >
2788 6 : std::numeric_limits<GUInt64>::max() / anNewDimSizes[0])
2789 : {
2790 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
2791 1 : return false;
2792 : }
2793 5 : nNewTotalSize64 *= anNewDimSizes[0];
2794 : // We restrict the size of the allocation so that all elements can be
2795 : // indexed by GPtrDiff_t
2796 5 : if (nNewTotalSize64 >
2797 5 : static_cast<size_t>(std::numeric_limits<GPtrDiff_t>::max()))
2798 : {
2799 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
2800 0 : return false;
2801 : }
2802 5 : const size_t nNewTotalSize = static_cast<size_t>(nNewTotalSize64);
2803 : GByte *pabyArray = static_cast<GByte *>(
2804 5 : VSI_REALLOC_VERBOSE(m_pabyArray, nNewTotalSize));
2805 5 : if (!pabyArray)
2806 1 : return false;
2807 4 : memset(pabyArray + m_nTotalSize, 0, nNewTotalSize - m_nTotalSize);
2808 4 : m_pabyArray = pabyArray;
2809 4 : m_nTotalSize = nNewTotalSize;
2810 :
2811 4 : if (bResizeOtherArrays)
2812 : {
2813 3 : if (!ResizeOtherArrays())
2814 0 : return false;
2815 :
2816 6 : auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[0]);
2817 3 : if (dim)
2818 : {
2819 3 : dim->SetSize(anNewDimSizes[0]);
2820 : }
2821 : else
2822 : {
2823 0 : CPLAssert(false);
2824 : }
2825 : }
2826 4 : return true;
2827 : }
2828 :
2829 : // General case where we modify other dimensions that the first one.
2830 :
2831 : // Create dummy dimensions at the new sizes
2832 16 : std::vector<std::shared_ptr<GDALDimension>> aoNewDims;
2833 30 : for (size_t i = 0; i < nDimCount; ++i)
2834 : {
2835 44 : aoNewDims.emplace_back(std::make_shared<MEMDimension>(
2836 44 : std::string(), dims[i]->GetName(), std::string(), std::string(),
2837 44 : anNewDimSizes[i]));
2838 : }
2839 :
2840 : // Create a temporary array
2841 : auto poTempMDArray =
2842 24 : Create(std::string(), std::string(), aoNewDims, GetDataType());
2843 8 : if (!poTempMDArray->Init())
2844 2 : return false;
2845 12 : std::vector<GUInt64> arrayStartIdx(nDimCount);
2846 12 : std::vector<size_t> count(nDimCount);
2847 12 : std::vector<GInt64> arrayStep(nDimCount, 1);
2848 12 : std::vector<GPtrDiff_t> bufferStride(nDimCount);
2849 22 : for (size_t i = nDimCount; i > 0;)
2850 : {
2851 16 : --i;
2852 16 : if (i == nDimCount - 1)
2853 6 : bufferStride[i] = 1;
2854 : else
2855 : {
2856 20 : bufferStride[i] = static_cast<GPtrDiff_t>(bufferStride[i + 1] *
2857 10 : dims[i + 1]->GetSize());
2858 : }
2859 16 : const auto nCount = std::min(anNewDimSizes[i], dims[i]->GetSize());
2860 16 : count[i] = static_cast<size_t>(nCount);
2861 : }
2862 : // Copy the current content into the array with the new layout
2863 12 : if (!poTempMDArray->Write(arrayStartIdx.data(), count.data(),
2864 6 : arrayStep.data(), bufferStride.data(),
2865 6 : GetDataType(), m_pabyArray))
2866 : {
2867 0 : return false;
2868 : }
2869 :
2870 : // Move content of the temporary array into the current array, and
2871 : // invalidate the temporary array
2872 6 : FreeArray();
2873 6 : m_bOwnArray = true;
2874 6 : m_pabyArray = poTempMDArray->m_pabyArray;
2875 6 : m_nTotalSize = poTempMDArray->m_nTotalSize;
2876 6 : m_anStrides = poTempMDArray->m_anStrides;
2877 :
2878 6 : poTempMDArray->m_bOwnArray = false;
2879 6 : poTempMDArray->m_pabyArray = nullptr;
2880 6 : poTempMDArray->m_nTotalSize = 0;
2881 :
2882 6 : if (bResizeOtherArrays && !ResizeOtherArrays())
2883 0 : return false;
2884 :
2885 : // Update dimension size
2886 22 : for (size_t i = 0; i < nDimCount; ++i)
2887 : {
2888 16 : if (anNewDimSizes[i] != dims[i]->GetSize())
2889 : {
2890 10 : auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]);
2891 5 : if (dim)
2892 : {
2893 5 : dim->SetSize(anNewDimSizes[i]);
2894 : }
2895 : else
2896 : {
2897 0 : CPLAssert(false);
2898 : }
2899 : }
2900 : }
2901 :
2902 6 : return true;
2903 : }
2904 :
2905 : /************************************************************************/
2906 : /* Rename() */
2907 : /************************************************************************/
2908 :
2909 3 : bool MEMMDArray::Rename(const std::string &osNewName)
2910 : {
2911 3 : if (!CheckValidAndErrorOutIfNot())
2912 0 : return false;
2913 3 : if (osNewName.empty())
2914 : {
2915 1 : CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
2916 1 : return false;
2917 : }
2918 :
2919 2 : if (auto poParentGroup =
2920 4 : std::dynamic_pointer_cast<MEMGroup>(m_poGroupWeak.lock()))
2921 : {
2922 2 : if (!poParentGroup->RenameArray(m_osName, osNewName))
2923 : {
2924 1 : return false;
2925 : }
2926 : }
2927 :
2928 1 : BaseRename(osNewName);
2929 :
2930 1 : return true;
2931 : }
2932 :
2933 : /************************************************************************/
2934 : /* NotifyChildrenOfRenaming() */
2935 : /************************************************************************/
2936 :
2937 3 : void MEMMDArray::NotifyChildrenOfRenaming()
2938 : {
2939 6 : for (const auto &oIter : m_oMapAttributes)
2940 3 : oIter.second->ParentRenamed(m_osFullName);
2941 3 : }
2942 :
2943 : /************************************************************************/
2944 : /* NotifyChildrenOfDeletion() */
2945 : /************************************************************************/
2946 :
2947 2 : void MEMMDArray::NotifyChildrenOfDeletion()
2948 : {
2949 4 : for (const auto &oIter : m_oMapAttributes)
2950 2 : oIter.second->ParentDeleted();
2951 2 : }
2952 :
2953 : /************************************************************************/
2954 : /* BuildDimensions() */
2955 : /************************************************************************/
2956 :
2957 : static std::vector<std::shared_ptr<GDALDimension>>
2958 650 : BuildDimensions(const std::vector<GUInt64> &anDimensions)
2959 : {
2960 650 : std::vector<std::shared_ptr<GDALDimension>> res;
2961 770 : for (size_t i = 0; i < anDimensions.size(); i++)
2962 : {
2963 240 : res.emplace_back(std::make_shared<GDALDimensionWeakIndexingVar>(
2964 240 : std::string(), CPLSPrintf("dim%u", static_cast<unsigned>(i)),
2965 360 : std::string(), std::string(), anDimensions[i]));
2966 : }
2967 650 : return res;
2968 : }
2969 :
2970 : /************************************************************************/
2971 : /* MEMAttribute() */
2972 : /************************************************************************/
2973 :
2974 650 : MEMAttribute::MEMAttribute(const std::string &osParentName,
2975 : const std::string &osName,
2976 : const std::vector<GUInt64> &anDimensions,
2977 650 : const GDALExtendedDataType &oType)
2978 : : GDALAbstractMDArray(osParentName, osName),
2979 650 : MEMAbstractMDArray(osParentName, osName, BuildDimensions(anDimensions),
2980 : oType),
2981 1300 : GDALAttribute(osParentName, osName)
2982 : {
2983 650 : }
2984 :
2985 : /************************************************************************/
2986 : /* MEMAttribute::Create() */
2987 : /************************************************************************/
2988 :
2989 : std::shared_ptr<MEMAttribute>
2990 650 : MEMAttribute::Create(const std::string &osParentName, const std::string &osName,
2991 : const std::vector<GUInt64> &anDimensions,
2992 : const GDALExtendedDataType &oType)
2993 : {
2994 : auto attr(std::shared_ptr<MEMAttribute>(
2995 1300 : new MEMAttribute(osParentName, osName, anDimensions, oType)));
2996 650 : attr->SetSelf(attr);
2997 650 : if (!attr->Init())
2998 0 : return nullptr;
2999 650 : return attr;
3000 : }
3001 :
3002 : /************************************************************************/
3003 : /* MEMAttribute::Create() */
3004 : /************************************************************************/
3005 :
3006 532 : std::shared_ptr<MEMAttribute> MEMAttribute::Create(
3007 : const std::shared_ptr<MEMGroup> &poParentGroup, const std::string &osName,
3008 : const std::vector<GUInt64> &anDimensions, const GDALExtendedDataType &oType)
3009 : {
3010 : const std::string osParentName =
3011 532 : (poParentGroup && poParentGroup->GetName().empty())
3012 532 : ?
3013 : // Case of the ZarrAttributeGroup::m_oGroup fake group
3014 515 : poParentGroup->GetFullName()
3015 34 : : ((poParentGroup == nullptr || poParentGroup->GetFullName() == "/"
3016 583 : ? "/"
3017 8 : : poParentGroup->GetFullName() + "/") +
3018 1596 : "_GLOBAL_");
3019 1064 : auto attr(Create(osParentName, osName, anDimensions, oType));
3020 532 : if (!attr)
3021 0 : return nullptr;
3022 532 : attr->m_poParent = poParentGroup;
3023 532 : return attr;
3024 : }
3025 :
3026 : /************************************************************************/
3027 : /* MEMAttribute::Create() */
3028 : /************************************************************************/
3029 :
3030 45 : std::shared_ptr<MEMAttribute> MEMAttribute::Create(
3031 : const std::shared_ptr<MEMMDArray> &poParentArray, const std::string &osName,
3032 : const std::vector<GUInt64> &anDimensions, const GDALExtendedDataType &oType)
3033 : {
3034 : auto attr(
3035 90 : Create(poParentArray->GetFullName(), osName, anDimensions, oType));
3036 45 : if (!attr)
3037 0 : return nullptr;
3038 45 : attr->m_poParent = poParentArray;
3039 45 : return attr;
3040 : }
3041 :
3042 : /************************************************************************/
3043 : /* Rename() */
3044 : /************************************************************************/
3045 :
3046 19 : bool MEMAttribute::Rename(const std::string &osNewName)
3047 : {
3048 19 : if (!CheckValidAndErrorOutIfNot())
3049 8 : return false;
3050 11 : if (osNewName.empty())
3051 : {
3052 1 : CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
3053 1 : return false;
3054 : }
3055 :
3056 10 : if (auto poParent = m_poParent.lock())
3057 : {
3058 10 : if (!poParent->RenameAttribute(m_osName, osNewName))
3059 : {
3060 2 : return false;
3061 : }
3062 : }
3063 :
3064 8 : BaseRename(osNewName);
3065 :
3066 8 : m_bModified = true;
3067 :
3068 8 : return true;
3069 : }
3070 :
3071 : /************************************************************************/
3072 : /* MEMDimension() */
3073 : /************************************************************************/
3074 :
3075 302 : MEMDimension::MEMDimension(const std::string &osParentName,
3076 : const std::string &osName, const std::string &osType,
3077 302 : const std::string &osDirection, GUInt64 nSize)
3078 : : GDALDimensionWeakIndexingVar(osParentName, osName, osType, osDirection,
3079 302 : nSize)
3080 : {
3081 302 : }
3082 :
3083 : /************************************************************************/
3084 : /* RegisterUsingArray() */
3085 : /************************************************************************/
3086 :
3087 348 : void MEMDimension::RegisterUsingArray(MEMMDArray *poArray)
3088 : {
3089 348 : m_oSetArrays.insert(poArray);
3090 348 : }
3091 :
3092 : /************************************************************************/
3093 : /* UnRegisterUsingArray() */
3094 : /************************************************************************/
3095 :
3096 374 : void MEMDimension::UnRegisterUsingArray(MEMMDArray *poArray)
3097 : {
3098 374 : m_oSetArrays.erase(poArray);
3099 374 : }
3100 :
3101 : /************************************************************************/
3102 : /* Create() */
3103 : /************************************************************************/
3104 :
3105 : /* static */
3106 : std::shared_ptr<MEMDimension>
3107 280 : MEMDimension::Create(const std::shared_ptr<MEMGroup> &poParentGroup,
3108 : const std::string &osName, const std::string &osType,
3109 : const std::string &osDirection, GUInt64 nSize)
3110 : {
3111 : auto newDim(std::make_shared<MEMDimension>(
3112 280 : poParentGroup->GetFullName(), osName, osType, osDirection, nSize));
3113 280 : newDim->m_poParentGroup = poParentGroup;
3114 280 : return newDim;
3115 : }
3116 :
3117 : /************************************************************************/
3118 : /* CreateDimension() */
3119 : /************************************************************************/
3120 :
3121 : std::shared_ptr<GDALDimension>
3122 284 : MEMGroup::CreateDimension(const std::string &osName, const std::string &osType,
3123 : const std::string &osDirection, GUInt64 nSize,
3124 : CSLConstList)
3125 : {
3126 284 : if (osName.empty())
3127 : {
3128 1 : CPLError(CE_Failure, CPLE_NotSupported,
3129 : "Empty dimension name not supported");
3130 1 : return nullptr;
3131 : }
3132 283 : if (m_oMapDimensions.find(osName) != m_oMapDimensions.end())
3133 : {
3134 3 : CPLError(CE_Failure, CPLE_AppDefined,
3135 : "A dimension with same name already exists");
3136 3 : return nullptr;
3137 : }
3138 : auto newDim(MEMDimension::Create(
3139 560 : std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()), osName, osType,
3140 560 : osDirection, nSize));
3141 280 : m_oMapDimensions[osName] = newDim;
3142 280 : return newDim;
3143 : }
3144 :
3145 : /************************************************************************/
3146 : /* Rename() */
3147 : /************************************************************************/
3148 :
3149 3 : bool MEMDimension::Rename(const std::string &osNewName)
3150 : {
3151 3 : if (osNewName.empty())
3152 : {
3153 1 : CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported");
3154 1 : return false;
3155 : }
3156 :
3157 2 : if (auto poParentGroup = m_poParentGroup.lock())
3158 : {
3159 2 : if (!poParentGroup->RenameDimension(m_osName, osNewName))
3160 : {
3161 1 : return false;
3162 : }
3163 : }
3164 :
3165 1 : BaseRename(osNewName);
3166 :
3167 1 : return true;
3168 : }
3169 :
3170 : /************************************************************************/
3171 : /* CreateMultiDimensional() */
3172 : /************************************************************************/
3173 :
3174 : GDALDataset *
3175 148 : MEMDataset::CreateMultiDimensional(const char *pszFilename,
3176 : CSLConstList /*papszRootGroupOptions*/,
3177 : CSLConstList /*papszOptions*/)
3178 : {
3179 148 : auto poDS = new MEMDataset();
3180 :
3181 148 : poDS->SetDescription(pszFilename);
3182 148 : auto poRootGroup = MEMGroup::Create(std::string(), nullptr);
3183 148 : poDS->m_poPrivate->m_poRootGroup = poRootGroup;
3184 :
3185 296 : return poDS;
3186 : }
3187 :
3188 : /************************************************************************/
3189 : /* GetRootGroup() */
3190 : /************************************************************************/
3191 :
3192 8157 : std::shared_ptr<GDALGroup> MEMDataset::GetRootGroup() const
3193 : {
3194 8157 : return m_poPrivate->m_poRootGroup;
3195 : }
3196 :
3197 : /************************************************************************/
3198 : /* MEMDatasetIdentify() */
3199 : /************************************************************************/
3200 :
3201 56902 : static int MEMDatasetIdentify(GDALOpenInfo *poOpenInfo)
3202 : {
3203 56915 : return (STARTS_WITH(poOpenInfo->pszFilename, "MEM:::") &&
3204 56915 : poOpenInfo->fpL == nullptr);
3205 : }
3206 :
3207 : /************************************************************************/
3208 : /* MEMDatasetDelete() */
3209 : /************************************************************************/
3210 :
3211 4 : static CPLErr MEMDatasetDelete(const char * /* fileName */)
3212 : {
3213 : /* Null implementation, so that people can Delete("MEM:::") */
3214 4 : return CE_None;
3215 : }
3216 :
3217 : /************************************************************************/
3218 : /* GDALRegister_MEM() */
3219 : /************************************************************************/
3220 :
3221 1595 : void GDALRegister_MEM()
3222 :
3223 : {
3224 1595 : if (GDALGetDriverByName("MEM") != nullptr)
3225 302 : return;
3226 :
3227 1293 : GDALDriver *poDriver = new GDALDriver();
3228 :
3229 1293 : poDriver->SetDescription("MEM");
3230 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
3231 1293 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
3232 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "In Memory Raster");
3233 1293 : poDriver->SetMetadataItem(
3234 : GDAL_DMD_CREATIONDATATYPES,
3235 : "Byte Int8 Int16 UInt16 Int32 UInt32 Int64 UInt64 Float32 Float64 "
3236 1293 : "CInt16 CInt32 CFloat32 CFloat64");
3237 1293 : poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES");
3238 :
3239 1293 : poDriver->SetMetadataItem(
3240 : GDAL_DMD_CREATIONOPTIONLIST,
3241 : "<CreationOptionList>"
3242 : " <Option name='INTERLEAVE' type='string-select' default='BAND'>"
3243 : " <Value>BAND</Value>"
3244 : " <Value>PIXEL</Value>"
3245 : " </Option>"
3246 1293 : "</CreationOptionList>");
3247 :
3248 : // Define GDAL_NO_OPEN_FOR_MEM_DRIVER macro to undefine Open() method for
3249 : // MEM driver. Otherwise, bad user input can trigger easily a GDAL crash
3250 : // as random pointers can be passed as a string. All code in GDAL tree
3251 : // using the MEM driver use the Create() method only, so Open() is not
3252 : // needed, except for esoteric uses.
3253 : #ifndef GDAL_NO_OPEN_FOR_MEM_DRIVER
3254 1293 : poDriver->pfnOpen = MEMDataset::Open;
3255 1293 : poDriver->pfnIdentify = MEMDatasetIdentify;
3256 : #endif
3257 1293 : poDriver->pfnCreate = MEMDataset::CreateBase;
3258 1293 : poDriver->pfnCreateMultiDimensional = MEMDataset::CreateMultiDimensional;
3259 1293 : poDriver->pfnDelete = MEMDatasetDelete;
3260 :
3261 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
3262 : }
|