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