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