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