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