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
33 #include <algorithm>
34 #include <climits>
35 #include <cstdlib>
36 #include <cstring>
37 #include <limits>
38 #include <vector>
39
40 #include "cpl_config.h"
41 #include "cpl_conv.h"
42 #include "cpl_error.h"
43 #include "cpl_minixml.h"
44 #include "cpl_progress.h"
45 #include "cpl_string.h"
46 #include "cpl_vsi.h"
47 #include "gdal.h"
48 #include "gdal_frmts.h"
49
50 CPL_CVSID("$Id: memdataset.cpp 3d710b50de5e050928417a62de7c3fd209a5b02c 2020-10-19 19:51:36 +0200 Even Rouault $")
51
52 struct MEMDataset::Private
53 {
54 std::shared_ptr<GDALGroup> m_poRootGroup{};
55 };
56
57 /************************************************************************/
58 /* MEMCreateRasterBand() */
59 /************************************************************************/
60
MEMCreateRasterBand(GDALDataset * poDS,int nBand,GByte * pabyData,GDALDataType eType,int nPixelOffset,int nLineOffset,int bAssumeOwnership)61 GDALRasterBandH MEMCreateRasterBand( GDALDataset *poDS, int nBand,
62 GByte *pabyData, GDALDataType eType,
63 int nPixelOffset, int nLineOffset,
64 int bAssumeOwnership )
65
66 {
67 return reinterpret_cast<GDALRasterBandH>(
68 new MEMRasterBand( poDS, nBand, pabyData, eType, nPixelOffset,
69 nLineOffset, bAssumeOwnership ) );
70 }
71
72 /************************************************************************/
73 /* MEMCreateRasterBandEx() */
74 /************************************************************************/
75
MEMCreateRasterBandEx(GDALDataset * poDS,int nBand,GByte * pabyData,GDALDataType eType,GSpacing nPixelOffset,GSpacing nLineOffset,int bAssumeOwnership)76 GDALRasterBandH MEMCreateRasterBandEx( GDALDataset *poDS, int nBand,
77 GByte *pabyData, GDALDataType eType,
78 GSpacing nPixelOffset,
79 GSpacing nLineOffset,
80 int bAssumeOwnership )
81
82 {
83 return reinterpret_cast<GDALRasterBandH>(
84 new MEMRasterBand( poDS, nBand, pabyData, eType, nPixelOffset,
85 nLineOffset, bAssumeOwnership ) );
86 }
87
88 /************************************************************************/
89 /* MEMRasterBand() */
90 /************************************************************************/
91
MEMRasterBand(GByte * pabyDataIn,GDALDataType eTypeIn,int nXSizeIn,int nYSizeIn)92 MEMRasterBand::MEMRasterBand( GByte *pabyDataIn, GDALDataType eTypeIn,
93 int nXSizeIn, int nYSizeIn ) :
94 GDALPamRasterBand(FALSE),
95 pabyData(pabyDataIn),
96 nPixelOffset(GDALGetDataTypeSizeBytes(eTypeIn)),
97 nLineOffset(0),
98 bOwnData(true),
99 bNoDataSet(FALSE),
100 dfNoData(0.0),
101 eColorInterp(GCI_Undefined),
102 dfOffset(0.0),
103 dfScale(1.0),
104 psSavedHistograms(nullptr)
105 {
106 eAccess = GA_Update;
107 eDataType = eTypeIn;
108 nRasterXSize = nXSizeIn;
109 nRasterYSize = nYSizeIn;
110 nBlockXSize = nXSizeIn;
111 nBlockYSize = 1;
112 nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize);
113 }
114
115 /************************************************************************/
116 /* MEMRasterBand() */
117 /************************************************************************/
118
MEMRasterBand(GDALDataset * poDSIn,int nBandIn,GByte * pabyDataIn,GDALDataType eTypeIn,GSpacing nPixelOffsetIn,GSpacing nLineOffsetIn,int bAssumeOwnership,const char * pszPixelType)119 MEMRasterBand::MEMRasterBand( GDALDataset *poDSIn, int nBandIn,
120 GByte *pabyDataIn, GDALDataType eTypeIn,
121 GSpacing nPixelOffsetIn, GSpacing nLineOffsetIn,
122 int bAssumeOwnership, const char * pszPixelType ) :
123 GDALPamRasterBand(FALSE),
124 pabyData(pabyDataIn),
125 nPixelOffset(nPixelOffsetIn),
126 nLineOffset(nLineOffsetIn),
127 bOwnData(bAssumeOwnership),
128 bNoDataSet(FALSE),
129 dfNoData(0.0),
130 eColorInterp(GCI_Undefined),
131 dfOffset(0.0),
132 dfScale(1.0),
133 psSavedHistograms(nullptr)
134 {
135 poDS = poDSIn;
136 nBand = nBandIn;
137
138 eAccess = poDS->GetAccess();
139
140 eDataType = eTypeIn;
141
142 nBlockXSize = poDS->GetRasterXSize();
143 nBlockYSize = 1;
144
145 if( nPixelOffsetIn == 0 )
146 nPixelOffset = GDALGetDataTypeSizeBytes(eTypeIn);
147
148 if( nLineOffsetIn == 0 )
149 nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize);
150
151 if( pszPixelType && EQUAL(pszPixelType,"SIGNEDBYTE") )
152 SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
153 }
154
155 /************************************************************************/
156 /* ~MEMRasterBand() */
157 /************************************************************************/
158
~MEMRasterBand()159 MEMRasterBand::~MEMRasterBand()
160
161 {
162 if( bOwnData )
163 {
164 VSIFree( pabyData );
165 }
166
167 if (psSavedHistograms != nullptr)
168 CPLDestroyXMLNode(psSavedHistograms);
169 }
170
171 /************************************************************************/
172 /* IReadBlock() */
173 /************************************************************************/
174
IReadBlock(CPL_UNUSED int nBlockXOff,int nBlockYOff,void * pImage)175 CPLErr MEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
176 int nBlockYOff,
177 void * pImage )
178 {
179 CPLAssert( nBlockXOff == 0 );
180
181 const int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
182
183 if( nPixelOffset == nWordSize )
184 {
185 memcpy( pImage,
186 pabyData + nLineOffset*(size_t)nBlockYOff,
187 static_cast<size_t>(nPixelOffset) * nBlockXSize );
188 }
189 else
190 {
191 GByte * const pabyCur =
192 pabyData + nLineOffset * static_cast<size_t>(nBlockYOff);
193
194 for( int iPixel = 0; iPixel < nBlockXSize; iPixel++ )
195 {
196 memcpy( reinterpret_cast<GByte *>(pImage) + iPixel*nWordSize,
197 pabyCur + iPixel*nPixelOffset,
198 nWordSize );
199 }
200 }
201
202 return CE_None;
203 }
204
205 /************************************************************************/
206 /* IWriteBlock() */
207 /************************************************************************/
208
IWriteBlock(CPL_UNUSED int nBlockXOff,int nBlockYOff,void * pImage)209 CPLErr MEMRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff,
210 int nBlockYOff,
211 void * pImage )
212 {
213 CPLAssert( nBlockXOff == 0 );
214 const int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
215
216 if( nPixelOffset == nWordSize )
217 {
218 memcpy( pabyData+nLineOffset*(size_t)nBlockYOff,
219 pImage,
220 static_cast<size_t>(nPixelOffset) * nBlockXSize );
221 }
222 else
223 {
224 GByte *pabyCur =
225 pabyData + nLineOffset * static_cast<size_t>(nBlockYOff);
226
227 for( int iPixel = 0; iPixel < nBlockXSize; iPixel++ )
228 {
229 memcpy( pabyCur + iPixel*nPixelOffset,
230 reinterpret_cast<GByte *>( pImage ) + iPixel*nWordSize,
231 nWordSize );
232 }
233 }
234
235 return CE_None;
236 }
237
238 /************************************************************************/
239 /* IRasterIO() */
240 /************************************************************************/
241
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpaceBuf,GSpacing nLineSpaceBuf,GDALRasterIOExtraArg * psExtraArg)242 CPLErr MEMRasterBand::IRasterIO( GDALRWFlag eRWFlag,
243 int nXOff, int nYOff, int nXSize, int nYSize,
244 void * pData, int nBufXSize, int nBufYSize,
245 GDALDataType eBufType,
246 GSpacing nPixelSpaceBuf,
247 GSpacing nLineSpaceBuf,
248 GDALRasterIOExtraArg* psExtraArg )
249 {
250 if( nXSize != nBufXSize || nYSize != nBufYSize )
251 {
252 return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
253 pData, nBufXSize, nBufYSize,
254 eBufType,
255 static_cast<int>(nPixelSpaceBuf),
256 nLineSpaceBuf,
257 psExtraArg);
258 }
259
260 // In case block based I/O has been done before.
261 FlushCache();
262
263 if( eRWFlag == GF_Read )
264 {
265 for( int iLine=0; iLine < nYSize; iLine++ )
266 {
267 GDALCopyWords(
268 pabyData + nLineOffset*static_cast<GPtrDiff_t>(iLine + nYOff) +
269 nXOff*nPixelOffset,
270 eDataType,
271 static_cast<int>(nPixelOffset),
272 reinterpret_cast<GByte*>( pData ) +
273 nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine),
274 eBufType,
275 static_cast<int>(nPixelSpaceBuf),
276 nXSize );
277 }
278 }
279 else
280 {
281 for( int iLine = 0; iLine < nYSize; iLine++ )
282 {
283 GDALCopyWords(
284 reinterpret_cast<GByte *>( pData ) +
285 nLineSpaceBuf*static_cast<GPtrDiff_t>(iLine),
286 eBufType,
287 static_cast<int>(nPixelSpaceBuf),
288 pabyData + nLineOffset*static_cast<GPtrDiff_t>(iLine + nYOff) +
289 nXOff*nPixelOffset,
290 eDataType,
291 static_cast<int>(nPixelOffset),
292 nXSize );
293 }
294 }
295 return CE_None;
296 }
297
298 /************************************************************************/
299 /* IRasterIO() */
300 /************************************************************************/
301
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GSpacing nPixelSpaceBuf,GSpacing nLineSpaceBuf,GSpacing nBandSpaceBuf,GDALRasterIOExtraArg * psExtraArg)302 CPLErr MEMDataset::IRasterIO( GDALRWFlag eRWFlag,
303 int nXOff, int nYOff, int nXSize, int nYSize,
304 void * pData, int nBufXSize, int nBufYSize,
305 GDALDataType eBufType,
306 int nBandCount, int *panBandMap,
307 GSpacing nPixelSpaceBuf,
308 GSpacing nLineSpaceBuf,
309 GSpacing nBandSpaceBuf,
310 GDALRasterIOExtraArg* psExtraArg)
311 {
312 const int eBufTypeSize = GDALGetDataTypeSize(eBufType) / 8;
313
314 // Detect if we have a pixel-interleaved buffer and a pixel-interleaved
315 // dataset.
316 if( nXSize == nBufXSize && nYSize == nBufYSize &&
317 nBandCount == nBands && nBands > 1 &&
318 nBandSpaceBuf == eBufTypeSize &&
319 nPixelSpaceBuf == nBandSpaceBuf * nBands )
320 {
321 GDALDataType eDT = GDT_Unknown;
322 GByte* pabyData = nullptr;
323 GSpacing nPixelOffset = 0;
324 GSpacing nLineOffset = 0;
325 int eDTSize = 0;
326 int iBandIndex;
327 for( iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++ )
328 {
329 if( panBandMap[iBandIndex] != iBandIndex + 1 )
330 break;
331
332 MEMRasterBand *poBand = reinterpret_cast<MEMRasterBand *>(
333 GetRasterBand(iBandIndex + 1) );
334 if( iBandIndex == 0 )
335 {
336 eDT = poBand->GetRasterDataType();
337 pabyData = poBand->pabyData;
338 nPixelOffset = poBand->nPixelOffset;
339 nLineOffset = poBand->nLineOffset;
340 eDTSize = GDALGetDataTypeSize(eDT) / 8;
341 if( nPixelOffset != static_cast<GSpacing>(nBands) * eDTSize )
342 break;
343 }
344 else if( poBand->GetRasterDataType() != eDT ||
345 nPixelOffset != poBand->nPixelOffset ||
346 nLineOffset != poBand->nLineOffset ||
347 poBand->pabyData != pabyData + iBandIndex * eDTSize )
348 {
349 break;
350 }
351 }
352 if( iBandIndex == nBandCount )
353 {
354 FlushCache();
355 if( eRWFlag == GF_Read )
356 {
357 for(int iLine=0;iLine<nYSize;iLine++)
358 {
359 GDALCopyWords(
360 pabyData +
361 nLineOffset*static_cast<size_t>(iLine + nYOff) +
362 nXOff*nPixelOffset,
363 eDT,
364 eDTSize,
365 reinterpret_cast<GByte *>( pData ) +
366 nLineSpaceBuf * static_cast<size_t>(iLine),
367 eBufType,
368 eBufTypeSize,
369 nXSize * nBands );
370 }
371 }
372 else
373 {
374 for(int iLine=0;iLine<nYSize;iLine++)
375 {
376 GDALCopyWords(
377 reinterpret_cast<GByte *>( pData ) +
378 nLineSpaceBuf*(size_t)iLine,
379 eBufType,
380 eBufTypeSize,
381 pabyData +
382 nLineOffset * static_cast<size_t>(iLine + nYOff) +
383 nXOff*nPixelOffset,
384 eDT,
385 eDTSize,
386 nXSize * nBands);
387 }
388 }
389 return CE_None;
390 }
391 }
392
393 if( nBufXSize != nXSize || nBufYSize != nYSize )
394 return GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
395 pData, nBufXSize, nBufYSize,
396 eBufType, nBandCount, panBandMap,
397 nPixelSpaceBuf, nLineSpaceBuf, nBandSpaceBuf,
398 psExtraArg );
399
400 return GDALDataset::BandBasedRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
401 pData, nBufXSize, nBufYSize,
402 eBufType, nBandCount, panBandMap,
403 nPixelSpaceBuf, nLineSpaceBuf, nBandSpaceBuf,
404 psExtraArg );
405 }
406
407 /************************************************************************/
408 /* GetNoDataValue() */
409 /************************************************************************/
GetNoDataValue(int * pbSuccess)410 double MEMRasterBand::GetNoDataValue( int *pbSuccess )
411
412 {
413 if( pbSuccess )
414 *pbSuccess = bNoDataSet;
415
416 if( bNoDataSet )
417 return dfNoData;
418
419 return 0.0;
420 }
421
422 /************************************************************************/
423 /* SetNoDataValue() */
424 /************************************************************************/
SetNoDataValue(double dfNewValue)425 CPLErr MEMRasterBand::SetNoDataValue( double dfNewValue )
426 {
427 dfNoData = dfNewValue;
428 bNoDataSet = TRUE;
429
430 return CE_None;
431 }
432
433 /************************************************************************/
434 /* DeleteNoDataValue() */
435 /************************************************************************/
436
DeleteNoDataValue()437 CPLErr MEMRasterBand::DeleteNoDataValue()
438 {
439 dfNoData = 0.0;
440 bNoDataSet = FALSE;
441
442 return CE_None;
443 }
444
445 /************************************************************************/
446 /* GetColorInterpretation() */
447 /************************************************************************/
448
GetColorInterpretation()449 GDALColorInterp MEMRasterBand::GetColorInterpretation()
450
451 {
452 if( m_poColorTable != nullptr )
453 return GCI_PaletteIndex;
454
455 return eColorInterp;
456 }
457
458 /************************************************************************/
459 /* SetColorInterpretation() */
460 /************************************************************************/
461
SetColorInterpretation(GDALColorInterp eGCI)462 CPLErr MEMRasterBand::SetColorInterpretation( GDALColorInterp eGCI )
463
464 {
465 eColorInterp = eGCI;
466
467 return CE_None;
468 }
469
470 /************************************************************************/
471 /* GetColorTable() */
472 /************************************************************************/
473
GetColorTable()474 GDALColorTable *MEMRasterBand::GetColorTable()
475
476 {
477 return m_poColorTable.get();
478 }
479
480 /************************************************************************/
481 /* SetColorTable() */
482 /************************************************************************/
483
SetColorTable(GDALColorTable * poCT)484 CPLErr MEMRasterBand::SetColorTable( GDALColorTable *poCT )
485
486 {
487 if( poCT == nullptr )
488 m_poColorTable.reset();
489 else
490 m_poColorTable.reset(poCT->Clone());
491
492 return CE_None;
493 }
494 /************************************************************************/
495 /* GetDefaultRAT() */
496 /************************************************************************/
497
GetDefaultRAT()498 GDALRasterAttributeTable* MEMRasterBand::GetDefaultRAT()
499 {
500 return m_poRAT.get();
501 }
502
503 /************************************************************************/
504 /* SetDefaultRAT() */
505 /************************************************************************/
506
SetDefaultRAT(const GDALRasterAttributeTable * poRAT)507 CPLErr MEMRasterBand::SetDefaultRAT( const GDALRasterAttributeTable * poRAT )
508 {
509 if( poRAT == nullptr )
510 m_poRAT.reset();
511 else
512 m_poRAT.reset(poRAT->Clone());
513
514 return CE_None;
515 }
516
517 /************************************************************************/
518 /* GetUnitType() */
519 /************************************************************************/
520
GetUnitType()521 const char *MEMRasterBand::GetUnitType()
522
523 {
524 return m_osUnitType.c_str();
525 }
526
527 /************************************************************************/
528 /* SetUnitType() */
529 /************************************************************************/
530
SetUnitType(const char * pszNewValue)531 CPLErr MEMRasterBand::SetUnitType( const char *pszNewValue )
532
533 {
534 m_osUnitType = pszNewValue ? pszNewValue : "";
535
536 return CE_None;
537 }
538
539 /************************************************************************/
540 /* GetOffset() */
541 /************************************************************************/
542
GetOffset(int * pbSuccess)543 double MEMRasterBand::GetOffset( int *pbSuccess )
544
545 {
546 if( pbSuccess != nullptr )
547 *pbSuccess = TRUE;
548
549 return dfOffset;
550 }
551
552 /************************************************************************/
553 /* SetOffset() */
554 /************************************************************************/
555
SetOffset(double dfNewOffset)556 CPLErr MEMRasterBand::SetOffset( double dfNewOffset )
557
558 {
559 dfOffset = dfNewOffset;
560 return CE_None;
561 }
562
563 /************************************************************************/
564 /* GetScale() */
565 /************************************************************************/
566
GetScale(int * pbSuccess)567 double MEMRasterBand::GetScale( int *pbSuccess )
568
569 {
570 if( pbSuccess != nullptr )
571 *pbSuccess = TRUE;
572
573 return dfScale;
574 }
575
576 /************************************************************************/
577 /* SetScale() */
578 /************************************************************************/
579
SetScale(double dfNewScale)580 CPLErr MEMRasterBand::SetScale( double dfNewScale )
581
582 {
583 dfScale = dfNewScale;
584 return CE_None;
585 }
586
587 /************************************************************************/
588 /* GetCategoryNames() */
589 /************************************************************************/
590
GetCategoryNames()591 char **MEMRasterBand::GetCategoryNames()
592
593 {
594 return m_aosCategoryNames.List();
595 }
596
597 /************************************************************************/
598 /* SetCategoryNames() */
599 /************************************************************************/
600
SetCategoryNames(char ** papszNewNames)601 CPLErr MEMRasterBand::SetCategoryNames( char ** papszNewNames )
602
603 {
604 m_aosCategoryNames = CSLDuplicate(papszNewNames);
605
606 return CE_None;
607 }
608
609 /************************************************************************/
610 /* SetDefaultHistogram() */
611 /************************************************************************/
612
SetDefaultHistogram(double dfMin,double dfMax,int nBuckets,GUIntBig * panHistogram)613 CPLErr MEMRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
614 int nBuckets, GUIntBig *panHistogram)
615
616 {
617 /* -------------------------------------------------------------------- */
618 /* Do we have a matching histogram we should replace? */
619 /* -------------------------------------------------------------------- */
620 CPLXMLNode *psNode = PamFindMatchingHistogram( psSavedHistograms,
621 dfMin, dfMax, nBuckets,
622 TRUE, TRUE );
623 if( psNode != nullptr )
624 {
625 /* blow this one away */
626 CPLRemoveXMLChild( psSavedHistograms, psNode );
627 CPLDestroyXMLNode( psNode );
628 }
629
630 /* -------------------------------------------------------------------- */
631 /* Translate into a histogram XML tree. */
632 /* -------------------------------------------------------------------- */
633 CPLXMLNode *psHistItem = PamHistogramToXMLTree( dfMin, dfMax, nBuckets,
634 panHistogram, TRUE, FALSE );
635 if( psHistItem == nullptr )
636 return CE_Failure;
637
638 /* -------------------------------------------------------------------- */
639 /* Insert our new default histogram at the front of the */
640 /* histogram list so that it will be the default histogram. */
641 /* -------------------------------------------------------------------- */
642
643 if( psSavedHistograms == nullptr )
644 psSavedHistograms = CPLCreateXMLNode( nullptr, CXT_Element,
645 "Histograms" );
646
647 psHistItem->psNext = psSavedHistograms->psChild;
648 psSavedHistograms->psChild = psHistItem;
649
650 return CE_None;
651 }
652
653 /************************************************************************/
654 /* GetDefaultHistogram() */
655 /************************************************************************/
656
657 CPLErr
GetDefaultHistogram(double * pdfMin,double * pdfMax,int * pnBuckets,GUIntBig ** ppanHistogram,int bForce,GDALProgressFunc pfnProgress,void * pProgressData)658 MEMRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
659 int *pnBuckets, GUIntBig **ppanHistogram,
660 int bForce,
661 GDALProgressFunc pfnProgress,
662 void *pProgressData )
663
664 {
665 if( psSavedHistograms != nullptr )
666 {
667 for( CPLXMLNode *psXMLHist = psSavedHistograms->psChild;
668 psXMLHist != nullptr;
669 psXMLHist = psXMLHist->psNext )
670 {
671 if( psXMLHist->eType != CXT_Element
672 || !EQUAL(psXMLHist->pszValue,"HistItem") )
673 continue;
674
675 int bApprox = FALSE;
676 int bIncludeOutOfRange = FALSE;
677 if( PamParseHistogram( psXMLHist, pdfMin, pdfMax, pnBuckets,
678 ppanHistogram, &bIncludeOutOfRange,
679 &bApprox ) )
680 return CE_None;
681
682 return CE_Failure;
683 }
684 }
685
686 return GDALRasterBand::GetDefaultHistogram( pdfMin, pdfMax, pnBuckets,
687 ppanHistogram, bForce,
688 pfnProgress,pProgressData);
689 }
690
691 /************************************************************************/
692 /* GetOverviewCount() */
693 /************************************************************************/
694
GetOverviewCount()695 int MEMRasterBand::GetOverviewCount()
696 {
697 MEMDataset* poMemDS = dynamic_cast<MEMDataset*>(poDS);
698 if( poMemDS == nullptr )
699 return 0;
700 return poMemDS->m_nOverviewDSCount;
701 }
702
703 /************************************************************************/
704 /* GetOverview() */
705 /************************************************************************/
706
GetOverview(int i)707 GDALRasterBand * MEMRasterBand::GetOverview( int i )
708
709 {
710 MEMDataset* poMemDS = dynamic_cast<MEMDataset*>(poDS);
711 if( poMemDS == nullptr )
712 return nullptr;
713 if( i < 0 || i >= poMemDS->m_nOverviewDSCount )
714 return nullptr;
715 return poMemDS->m_papoOverviewDS[i]->GetRasterBand(nBand);
716 }
717
718 /************************************************************************/
719 /* CreateMaskBand() */
720 /************************************************************************/
721
CreateMaskBand(int nFlagsIn)722 CPLErr MEMRasterBand::CreateMaskBand( int nFlagsIn )
723 {
724 InvalidateMaskBand();
725
726 MEMDataset* poMemDS = dynamic_cast<MEMDataset*>(poDS);
727 if( (nFlagsIn & GMF_PER_DATASET) != 0 && nBand != 1 && poMemDS != nullptr )
728 {
729 MEMRasterBand* poFirstBand =
730 reinterpret_cast<MEMRasterBand*>(poMemDS->GetRasterBand(1));
731 if( poFirstBand != nullptr)
732 return poFirstBand->CreateMaskBand( nFlagsIn );
733 }
734
735 GByte* pabyMaskData = static_cast<GByte*>(VSI_CALLOC_VERBOSE(nRasterXSize,
736 nRasterYSize));
737 if( pabyMaskData == nullptr )
738 return CE_Failure;
739
740 nMaskFlags = nFlagsIn;
741 bOwnMask = true;
742 poMask = new MEMRasterBand( pabyMaskData, GDT_Byte,
743 nRasterXSize, nRasterYSize );
744 if( (nFlagsIn & GMF_PER_DATASET) != 0 && nBand == 1 && poMemDS != nullptr )
745 {
746 for( int i = 2; i <= poMemDS->GetRasterCount(); ++i )
747 {
748 MEMRasterBand* poOtherBand =
749 reinterpret_cast<MEMRasterBand*>(poMemDS->GetRasterBand(i));
750 poOtherBand->InvalidateMaskBand();
751 poOtherBand->nMaskFlags = nFlagsIn;
752 poOtherBand->bOwnMask = false;
753 poOtherBand->poMask = poMask;
754 }
755 }
756 return CE_None;
757 }
758
759 /************************************************************************/
760 /* ==================================================================== */
761 /* MEMDataset */
762 /* ==================================================================== */
763 /************************************************************************/
764
765 /************************************************************************/
766 /* MEMDataset() */
767 /************************************************************************/
768
MEMDataset()769 MEMDataset::MEMDataset() :
770 GDALDataset(FALSE),
771 bGeoTransformSet(FALSE),
772 pszProjection(nullptr),
773 m_nGCPCount(0),
774 m_pasGCPs(nullptr),
775 m_nOverviewDSCount(0),
776 m_papoOverviewDS(nullptr),
777 m_poPrivate(new Private())
778 {
779 adfGeoTransform[0] = 0.0;
780 adfGeoTransform[1] = 1.0;
781 adfGeoTransform[2] = 0.0;
782 adfGeoTransform[3] = 0.0;
783 adfGeoTransform[4] = 0.0;
784 adfGeoTransform[5] = -1.0;
785 DisableReadWriteMutex();
786 }
787
788 /************************************************************************/
789 /* ~MEMDataset() */
790 /************************************************************************/
791
~MEMDataset()792 MEMDataset::~MEMDataset()
793
794 {
795 FlushCache();
796 CPLFree( pszProjection );
797
798 GDALDeinitGCPs( m_nGCPCount, m_pasGCPs );
799 CPLFree( m_pasGCPs );
800
801 for(int i=0;i<m_nOverviewDSCount;++i)
802 delete m_papoOverviewDS[i];
803 CPLFree(m_papoOverviewDS);
804 }
805
806 #if 0
807 /************************************************************************/
808 /* EnterReadWrite() */
809 /************************************************************************/
810
811 int MEMDataset::EnterReadWrite(CPL_UNUSED GDALRWFlag eRWFlag)
812 {
813 return TRUE;
814 }
815
816 /************************************************************************/
817 /* LeaveReadWrite() */
818 /************************************************************************/
819
820 void MEMDataset::LeaveReadWrite()
821 {
822 }
823 #endif // if 0
824
825 /************************************************************************/
826 /* GetProjectionRef() */
827 /************************************************************************/
828
_GetProjectionRef()829 const char *MEMDataset::_GetProjectionRef()
830
831 {
832 if( pszProjection == nullptr )
833 return "";
834
835 return pszProjection;
836 }
837
838 /************************************************************************/
839 /* SetProjection() */
840 /************************************************************************/
841
_SetProjection(const char * pszProjectionIn)842 CPLErr MEMDataset::_SetProjection( const char *pszProjectionIn )
843
844 {
845 CPLFree( pszProjection );
846 pszProjection = CPLStrdup( pszProjectionIn );
847
848 return CE_None;
849 }
850
851 /************************************************************************/
852 /* GetGeoTransform() */
853 /************************************************************************/
854
GetGeoTransform(double * padfGeoTransform)855 CPLErr MEMDataset::GetGeoTransform( double *padfGeoTransform )
856
857 {
858 memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
859 if( bGeoTransformSet )
860 return CE_None;
861
862 return CE_Failure;
863 }
864
865 /************************************************************************/
866 /* SetGeoTransform() */
867 /************************************************************************/
868
SetGeoTransform(double * padfGeoTransform)869 CPLErr MEMDataset::SetGeoTransform( double *padfGeoTransform )
870
871 {
872 memcpy( adfGeoTransform, padfGeoTransform, sizeof(double) * 6 );
873 bGeoTransformSet = TRUE;
874
875 return CE_None;
876 }
877
878 /************************************************************************/
879 /* GetInternalHandle() */
880 /************************************************************************/
881
GetInternalHandle(const char * pszRequest)882 void *MEMDataset::GetInternalHandle( const char * pszRequest )
883
884 {
885 // check for MEMORYnnn string in pszRequest (nnnn can be up to 10
886 // digits, or even omitted)
887 if( STARTS_WITH_CI(pszRequest, "MEMORY"))
888 {
889 if(int BandNumber = static_cast<int>(CPLScanLong(&pszRequest[6], 10)))
890 {
891 MEMRasterBand *RequestedRasterBand =
892 reinterpret_cast<MEMRasterBand *>( GetRasterBand(BandNumber) );
893
894 // we're within a MEMDataset so the only thing a RasterBand
895 // could be is a MEMRasterBand
896
897 if( RequestedRasterBand != nullptr )
898 {
899 // return the internal band data pointer
900 return RequestedRasterBand->GetData();
901 }
902 }
903 }
904
905 return nullptr;
906 }
907 /************************************************************************/
908 /* GetGCPCount() */
909 /************************************************************************/
910
GetGCPCount()911 int MEMDataset::GetGCPCount()
912
913 {
914 return m_nGCPCount;
915 }
916
917 /************************************************************************/
918 /* GetGCPProjection() */
919 /************************************************************************/
920
_GetGCPProjection()921 const char *MEMDataset::_GetGCPProjection()
922
923 {
924 return osGCPProjection;
925 }
926
927 /************************************************************************/
928 /* GetGCPs() */
929 /************************************************************************/
930
GetGCPs()931 const GDAL_GCP *MEMDataset::GetGCPs()
932
933 {
934 return m_pasGCPs;
935 }
936
937 /************************************************************************/
938 /* SetGCPs() */
939 /************************************************************************/
940
_SetGCPs(int nNewCount,const GDAL_GCP * pasNewGCPList,const char * pszGCPProjection)941 CPLErr MEMDataset::_SetGCPs( int nNewCount, const GDAL_GCP *pasNewGCPList,
942 const char *pszGCPProjection )
943
944 {
945 GDALDeinitGCPs( m_nGCPCount, m_pasGCPs );
946 CPLFree( m_pasGCPs );
947
948 if( pszGCPProjection == nullptr )
949 osGCPProjection = "";
950 else
951 osGCPProjection = pszGCPProjection;
952
953 m_nGCPCount = nNewCount;
954 m_pasGCPs = GDALDuplicateGCPs( m_nGCPCount, pasNewGCPList );
955
956 return CE_None;
957 }
958
959 /************************************************************************/
960 /* AddBand() */
961 /* */
962 /* Add a new band to the dataset, allowing creation options to */
963 /* specify the existing memory to use, otherwise create new */
964 /* memory. */
965 /************************************************************************/
966
AddBand(GDALDataType eType,char ** papszOptions)967 CPLErr MEMDataset::AddBand( GDALDataType eType, char **papszOptions )
968
969 {
970 const int nBandId = GetRasterCount() + 1;
971 const GSpacing nPixelSize = GDALGetDataTypeSizeBytes(eType);
972
973 /* -------------------------------------------------------------------- */
974 /* Do we need to allocate the memory ourselves? This is the */
975 /* simple case. */
976 /* -------------------------------------------------------------------- */
977 if( CSLFetchNameValue( papszOptions, "DATAPOINTER" ) == nullptr )
978 {
979 const GSpacing nTmp = nPixelSize * GetRasterXSize();
980 GByte* pData =
981 #if SIZEOF_VOIDP == 4
982 ( nTmp > INT_MAX ) ? nullptr :
983 #endif
984 reinterpret_cast<GByte *>(
985 VSI_CALLOC_VERBOSE((size_t)nTmp, GetRasterYSize() ) );
986
987 if( pData == nullptr )
988 {
989 return CE_Failure;
990 }
991
992 SetBand( nBandId,
993 new MEMRasterBand( this, nBandId, pData, eType, nPixelSize,
994 nPixelSize * GetRasterXSize(), TRUE ) );
995
996 return CE_None;
997 }
998
999 /* -------------------------------------------------------------------- */
1000 /* Get layout of memory and other flags. */
1001 /* -------------------------------------------------------------------- */
1002 const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER");
1003 GByte *pData = reinterpret_cast<GByte *>(
1004 CPLScanPointer( pszDataPointer,
1005 static_cast<int>(strlen(pszDataPointer)) ) );
1006
1007 const char *pszOption = CSLFetchNameValue(papszOptions, "PIXELOFFSET");
1008 GSpacing nPixelOffset;
1009 if( pszOption == nullptr )
1010 nPixelOffset = nPixelSize;
1011 else
1012 nPixelOffset = CPLAtoGIntBig(pszOption);
1013
1014 pszOption = CSLFetchNameValue(papszOptions, "LINEOFFSET");
1015 GSpacing nLineOffset;
1016 if( pszOption == nullptr )
1017 nLineOffset = GetRasterXSize() * static_cast<size_t>( nPixelOffset );
1018 else
1019 nLineOffset = CPLAtoGIntBig(pszOption);
1020
1021 SetBand( nBandId,
1022 new MEMRasterBand( this, nBandId, pData, eType,
1023 nPixelOffset, nLineOffset, FALSE ) );
1024
1025 return CE_None;
1026 }
1027
1028 /************************************************************************/
1029 /* IBuildOverviews() */
1030 /************************************************************************/
1031
IBuildOverviews(const char * pszResampling,int nOverviews,int * panOverviewList,int nListBands,int * panBandList,GDALProgressFunc pfnProgress,void * pProgressData)1032 CPLErr MEMDataset::IBuildOverviews( const char *pszResampling,
1033 int nOverviews, int *panOverviewList,
1034 int nListBands, int *panBandList,
1035 GDALProgressFunc pfnProgress,
1036 void * pProgressData )
1037 {
1038 if( nBands == 0 )
1039 {
1040 CPLError( CE_Failure, CPLE_NotSupported,
1041 "Dataset has zero bands." );
1042 return CE_Failure;
1043 }
1044
1045 if( nListBands != nBands )
1046 {
1047 CPLError( CE_Failure, CPLE_NotSupported,
1048 "Generation of overviews in MEM only"
1049 "supported when operating on all bands." );
1050 return CE_Failure;
1051 }
1052
1053 if( nOverviews == 0 )
1054 {
1055 // Cleanup existing overviews
1056 for(int i=0;i<m_nOverviewDSCount;++i)
1057 delete m_papoOverviewDS[i];
1058 CPLFree(m_papoOverviewDS);
1059 m_nOverviewDSCount = 0;
1060 m_papoOverviewDS = nullptr;
1061 return CE_None;
1062 }
1063
1064 /* -------------------------------------------------------------------- */
1065 /* Force cascading. Help to get accurate results when masks are */
1066 /* involved. */
1067 /* -------------------------------------------------------------------- */
1068 if( nOverviews > 1 &&
1069 (STARTS_WITH_CI(pszResampling, "AVER") |
1070 STARTS_WITH_CI(pszResampling, "GAUSS") ||
1071 EQUAL(pszResampling, "CUBIC") ||
1072 EQUAL(pszResampling, "CUBICSPLINE") ||
1073 EQUAL(pszResampling, "LANCZOS") ||
1074 EQUAL(pszResampling, "BILINEAR")) )
1075 {
1076 double dfTotalPixels = 0;
1077 for( int i = 0; i < nOverviews; i++ )
1078 {
1079 dfTotalPixels +=
1080 static_cast<double>(nRasterXSize) * nRasterYSize /
1081 (panOverviewList[i] * panOverviewList[i]);
1082 }
1083
1084 double dfAccPixels = 0;
1085 for( int i = 0; i < nOverviews; i++ )
1086 {
1087 double dfPixels =
1088 static_cast<double>(nRasterXSize) * nRasterYSize /
1089 (panOverviewList[i] * panOverviewList[i]);
1090 void* pScaledProgress = GDALCreateScaledProgress(
1091 dfAccPixels / dfTotalPixels,
1092 (dfAccPixels + dfPixels) / dfTotalPixels,
1093 pfnProgress, pProgressData );
1094 CPLErr eErr = IBuildOverviews(
1095 pszResampling,
1096 1, &panOverviewList[i],
1097 nListBands, panBandList,
1098 GDALScaledProgress,
1099 pScaledProgress );
1100 GDALDestroyScaledProgress( pScaledProgress );
1101 dfAccPixels += dfPixels;
1102 if( eErr == CE_Failure )
1103 return eErr;
1104 }
1105 return CE_None;
1106 }
1107
1108 /* -------------------------------------------------------------------- */
1109 /* Establish which of the overview levels we already have, and */
1110 /* which are new. */
1111 /* -------------------------------------------------------------------- */
1112 GDALRasterBand *poBand = GetRasterBand( 1 );
1113
1114 for( int i = 0; i < nOverviews; i++ )
1115 {
1116 bool bExisting = false;
1117 for( int j = 0; j < poBand->GetOverviewCount(); j++ )
1118 {
1119 GDALRasterBand * poOverview = poBand->GetOverview( j );
1120 if( poOverview == nullptr )
1121 continue;
1122
1123 int nOvFactor =
1124 GDALComputeOvFactor(poOverview->GetXSize(),
1125 poBand->GetXSize(),
1126 poOverview->GetYSize(),
1127 poBand->GetYSize());
1128
1129 if( nOvFactor == panOverviewList[i]
1130 || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i],
1131 poBand->GetXSize(),
1132 poBand->GetYSize() ) )
1133 {
1134 bExisting = true;
1135 break;
1136 }
1137 }
1138
1139 // Create new overview dataset if needed.
1140 if( !bExisting )
1141 {
1142 MEMDataset* poOvrDS = new MEMDataset();
1143 poOvrDS->eAccess = GA_Update;
1144 poOvrDS->nRasterXSize = (nRasterXSize + panOverviewList[i] - 1)
1145 / panOverviewList[i];
1146 poOvrDS->nRasterYSize = (nRasterYSize + panOverviewList[i] - 1)
1147 / panOverviewList[i];
1148 for( int iBand = 0; iBand < nBands; iBand ++ )
1149 {
1150 const GDALDataType eDT =
1151 GetRasterBand(iBand+1)->GetRasterDataType();
1152 if( poOvrDS->AddBand( eDT, nullptr ) != CE_None )
1153 {
1154 delete poOvrDS;
1155 return CE_Failure;
1156 }
1157 }
1158 m_nOverviewDSCount ++;
1159 m_papoOverviewDS = (GDALDataset**) CPLRealloc(m_papoOverviewDS,
1160 sizeof(GDALDataset*) * m_nOverviewDSCount );
1161 m_papoOverviewDS[m_nOverviewDSCount-1] = poOvrDS;
1162 }
1163 }
1164
1165 /* -------------------------------------------------------------------- */
1166 /* Build band list. */
1167 /* -------------------------------------------------------------------- */
1168 GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
1169 CPLCalloc(sizeof(GDALRasterBand *), nBands) );
1170 for( int i = 0; i < nBands; i++ )
1171 pahBands[i] = GetRasterBand( panBandList[i] );
1172
1173 /* -------------------------------------------------------------------- */
1174 /* Refresh overviews that were listed. */
1175 /* -------------------------------------------------------------------- */
1176 GDALRasterBand **papoOverviewBands = static_cast<GDALRasterBand **>(
1177 CPLCalloc(sizeof(void*), nOverviews) );
1178 GDALRasterBand **papoMaskOverviewBands = static_cast<GDALRasterBand **>(
1179 CPLCalloc(sizeof(void*), nOverviews) );
1180
1181 CPLErr eErr = CE_None;
1182 for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
1183 {
1184 poBand = GetRasterBand( panBandList[iBand] );
1185
1186 int nNewOverviews = 0;
1187 for( int i = 0; i < nOverviews; i++ )
1188 {
1189 for( int j = 0; j < poBand->GetOverviewCount(); j++ )
1190 {
1191 GDALRasterBand * poOverview = poBand->GetOverview( j );
1192
1193 int bHasNoData = FALSE;
1194 double noDataValue = poBand->GetNoDataValue(&bHasNoData);
1195
1196 if( bHasNoData )
1197 poOverview->SetNoDataValue(noDataValue);
1198
1199 const int nOvFactor =
1200 GDALComputeOvFactor(poOverview->GetXSize(),
1201 poBand->GetXSize(),
1202 poOverview->GetYSize(),
1203 poBand->GetYSize());
1204
1205 if( nOvFactor == panOverviewList[i]
1206 || nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1207 poBand->GetXSize(),
1208 poBand->GetYSize() ) )
1209 {
1210 papoOverviewBands[nNewOverviews++] = poOverview;
1211 break;
1212 }
1213 }
1214 }
1215
1216 // If the band has an explicit mask, we need to create overviews
1217 // for it
1218 MEMRasterBand* poMEMBand = reinterpret_cast<MEMRasterBand*>(poBand);
1219 const bool bMustGenerateMaskOvr =
1220 ( (poMEMBand->bOwnMask && poMEMBand->poMask != nullptr) ||
1221 // Or if it is a per-dataset mask, in which case just do it for the
1222 // first band
1223 ((poMEMBand->nMaskFlags & GMF_PER_DATASET) != 0 && iBand == 0) );
1224
1225 if( nNewOverviews > 0 && bMustGenerateMaskOvr )
1226 {
1227 for( int i = 0; i < nNewOverviews; i++ )
1228 {
1229 MEMRasterBand* poMEMOvrBand =
1230 reinterpret_cast<MEMRasterBand*>(papoOverviewBands[i]);
1231 if( !(poMEMOvrBand->bOwnMask && poMEMOvrBand->poMask != nullptr) &&
1232 (poMEMOvrBand->nMaskFlags & GMF_PER_DATASET) == 0 )
1233 {
1234 poMEMOvrBand->CreateMaskBand( poMEMBand->nMaskFlags );
1235 }
1236 papoMaskOverviewBands[i] = poMEMOvrBand->GetMaskBand();
1237 }
1238
1239 void* pScaledProgress = GDALCreateScaledProgress(
1240 1.0 * iBand / nBands,
1241 1.0 * (iBand+0.5) / nBands,
1242 pfnProgress, pProgressData );
1243
1244 MEMRasterBand* poMaskBand = reinterpret_cast<MEMRasterBand*>(
1245 poBand->GetMaskBand());
1246 // Make the mask band to be its own mask, similarly to what is
1247 // done for alpha bands in GDALRegenerateOverviews() (#5640)
1248 poMaskBand->InvalidateMaskBand();
1249 poMaskBand->bOwnMask = false;
1250 poMaskBand->poMask = poMaskBand;
1251 poMaskBand->nMaskFlags = 0;
1252 eErr = GDALRegenerateOverviews(
1253 (GDALRasterBandH) poMaskBand,
1254 nNewOverviews,
1255 (GDALRasterBandH*)papoMaskOverviewBands,
1256 pszResampling,
1257 GDALScaledProgress, pScaledProgress );
1258 poMaskBand->InvalidateMaskBand();
1259 GDALDestroyScaledProgress( pScaledProgress );
1260 }
1261
1262 // Generate overview of bands *AFTER* mask overviews
1263 if( nNewOverviews > 0 && eErr == CE_None )
1264 {
1265 void* pScaledProgress = GDALCreateScaledProgress(
1266 1.0 * (iBand+(bMustGenerateMaskOvr ? 0.5 : 1)) / nBands,
1267 1.0 * (iBand+1)/ nBands,
1268 pfnProgress, pProgressData );
1269 eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
1270 nNewOverviews,
1271 (GDALRasterBandH*)papoOverviewBands,
1272 pszResampling,
1273 GDALScaledProgress, pScaledProgress );
1274 GDALDestroyScaledProgress( pScaledProgress );
1275 }
1276 }
1277
1278 /* -------------------------------------------------------------------- */
1279 /* Cleanup */
1280 /* -------------------------------------------------------------------- */
1281 CPLFree( papoOverviewBands );
1282 CPLFree( papoMaskOverviewBands );
1283 CPLFree( pahBands );
1284
1285 return eErr;
1286 }
1287
1288 /************************************************************************/
1289 /* CreateMaskBand() */
1290 /************************************************************************/
1291
CreateMaskBand(int nFlagsIn)1292 CPLErr MEMDataset::CreateMaskBand( int nFlagsIn )
1293 {
1294 GDALRasterBand* poFirstBand = GetRasterBand(1);
1295 if( poFirstBand == nullptr )
1296 return CE_Failure;
1297 return poFirstBand->CreateMaskBand( nFlagsIn | GMF_PER_DATASET );
1298 }
1299
1300 /************************************************************************/
1301 /* Open() */
1302 /************************************************************************/
1303
Open(GDALOpenInfo * poOpenInfo)1304 GDALDataset *MEMDataset::Open( GDALOpenInfo * poOpenInfo )
1305
1306 {
1307 /* -------------------------------------------------------------------- */
1308 /* Do we have the special filename signature for MEM format */
1309 /* description strings? */
1310 /* -------------------------------------------------------------------- */
1311 if( !STARTS_WITH_CI(poOpenInfo->pszFilename, "MEM:::")
1312 || poOpenInfo->fpL != nullptr )
1313 return nullptr;
1314
1315 char **papszOptions
1316 = CSLTokenizeStringComplex(poOpenInfo->pszFilename+6, ",",
1317 TRUE, FALSE );
1318
1319 /* -------------------------------------------------------------------- */
1320 /* Verify we have all required fields */
1321 /* -------------------------------------------------------------------- */
1322 if( CSLFetchNameValue( papszOptions, "PIXELS" ) == nullptr
1323 || CSLFetchNameValue( papszOptions, "LINES" ) == nullptr
1324 || CSLFetchNameValue( papszOptions, "DATAPOINTER" ) == nullptr )
1325 {
1326 CPLError(
1327 CE_Failure, CPLE_AppDefined,
1328 "Missing required field (one of PIXELS, LINES or DATAPOINTER). "
1329 "Unable to access in-memory array." );
1330
1331 CSLDestroy( papszOptions );
1332 return nullptr;
1333 }
1334
1335 /* -------------------------------------------------------------------- */
1336 /* Create the new MEMDataset object. */
1337 /* -------------------------------------------------------------------- */
1338 MEMDataset *poDS = new MEMDataset();
1339
1340 poDS->nRasterXSize = atoi(CSLFetchNameValue(papszOptions,"PIXELS"));
1341 poDS->nRasterYSize = atoi(CSLFetchNameValue(papszOptions,"LINES"));
1342 poDS->eAccess = poOpenInfo->eAccess;
1343
1344 /* -------------------------------------------------------------------- */
1345 /* Extract other information. */
1346 /* -------------------------------------------------------------------- */
1347 const char *pszOption = CSLFetchNameValue(papszOptions,"BANDS");
1348 int nBands = 1;
1349 if( pszOption != nullptr )
1350 {
1351 nBands = atoi(pszOption);
1352 }
1353
1354 if( !GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
1355 !GDALCheckBandCount(nBands, TRUE))
1356 {
1357 CSLDestroy( papszOptions );
1358 delete poDS;
1359 return nullptr;
1360 }
1361
1362 pszOption = CSLFetchNameValue(papszOptions,"DATATYPE");
1363 GDALDataType eType = GDT_Byte;
1364 if( pszOption != nullptr )
1365 {
1366 if( atoi(pszOption) > 0 && atoi(pszOption) < GDT_TypeCount )
1367 eType = static_cast<GDALDataType>( atoi(pszOption) );
1368 else
1369 {
1370 eType = GDT_Unknown;
1371 for( int iType = 0; iType < GDT_TypeCount; iType++ )
1372 {
1373 if( EQUAL(GDALGetDataTypeName((GDALDataType) iType),
1374 pszOption) )
1375 {
1376 eType = static_cast<GDALDataType>( iType );
1377 break;
1378 }
1379 }
1380
1381 if( eType == GDT_Unknown )
1382 {
1383 CPLError( CE_Failure, CPLE_AppDefined,
1384 "DATATYPE=%s not recognised.",
1385 pszOption );
1386 CSLDestroy( papszOptions );
1387 delete poDS;
1388 return nullptr;
1389 }
1390 }
1391 }
1392
1393 pszOption = CSLFetchNameValue(papszOptions, "PIXELOFFSET");
1394 GSpacing nPixelOffset;
1395 if( pszOption == nullptr )
1396 nPixelOffset = GDALGetDataTypeSizeBytes(eType);
1397 else
1398 nPixelOffset = CPLScanUIntBig(pszOption,
1399 static_cast<int>(strlen(pszOption)));
1400
1401 pszOption = CSLFetchNameValue(papszOptions, "LINEOFFSET");
1402 GSpacing nLineOffset = 0;
1403 if( pszOption == nullptr )
1404 nLineOffset = poDS->nRasterXSize * static_cast<size_t>( nPixelOffset );
1405 else
1406 nLineOffset = CPLScanUIntBig(pszOption,
1407 static_cast<int>(strlen(pszOption)));
1408
1409 pszOption = CSLFetchNameValue(papszOptions, "BANDOFFSET");
1410 GSpacing nBandOffset = 0;
1411 if( pszOption == nullptr )
1412 nBandOffset = nLineOffset * static_cast<size_t>( poDS->nRasterYSize );
1413 else
1414 nBandOffset = CPLScanUIntBig(pszOption,
1415 static_cast<int>(strlen(pszOption)));
1416
1417 const char *pszDataPointer = CSLFetchNameValue(papszOptions,"DATAPOINTER");
1418 GByte *pabyData = reinterpret_cast<GByte *>(
1419 CPLScanPointer( pszDataPointer,
1420 static_cast<int>(strlen(pszDataPointer)) ) );
1421
1422 /* -------------------------------------------------------------------- */
1423 /* Create band information objects. */
1424 /* -------------------------------------------------------------------- */
1425 for( int iBand = 0; iBand < nBands; iBand++ )
1426 {
1427 poDS->SetBand( iBand+1,
1428 new MEMRasterBand( poDS, iBand+1,
1429 pabyData + iBand * nBandOffset,
1430 eType, nPixelOffset, nLineOffset,
1431 FALSE ) );
1432 }
1433
1434 /* -------------------------------------------------------------------- */
1435 /* Try to return a regular handle on the file. */
1436 /* -------------------------------------------------------------------- */
1437 CSLDestroy( papszOptions );
1438 return poDS;
1439 }
1440
1441 /************************************************************************/
1442 /* Create() */
1443 /************************************************************************/
1444
Create(const char *,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszOptions)1445 GDALDataset *MEMDataset::Create( const char * /* pszFilename */,
1446 int nXSize,
1447 int nYSize,
1448 int nBands,
1449 GDALDataType eType,
1450 char **papszOptions )
1451 {
1452
1453 /* -------------------------------------------------------------------- */
1454 /* Do we want a pixel interleaved buffer? I mostly care about */
1455 /* this to test pixel interleaved IO in other contexts, but it */
1456 /* could be useful to create a directly accessible buffer for */
1457 /* some apps. */
1458 /* -------------------------------------------------------------------- */
1459 bool bPixelInterleaved = false;
1460 const char *pszOption = CSLFetchNameValue( papszOptions, "INTERLEAVE" );
1461 if( pszOption && EQUAL(pszOption,"PIXEL") )
1462 bPixelInterleaved = true;
1463
1464 /* -------------------------------------------------------------------- */
1465 /* First allocate band data, verifying that we can get enough */
1466 /* memory. */
1467 /* -------------------------------------------------------------------- */
1468 const int nWordSize = GDALGetDataTypeSize(eType) / 8;
1469 if( nBands > 0 && nWordSize > 0 && (nBands > INT_MAX / nWordSize ||
1470 (GIntBig)nXSize * nYSize > GINTBIG_MAX / (nWordSize * nBands)) )
1471 {
1472 CPLError( CE_Failure, CPLE_OutOfMemory, "Multiplication overflow");
1473 return nullptr;
1474 }
1475
1476 const GUIntBig nGlobalBigSize
1477 = static_cast<GUIntBig>(nWordSize) * nBands * nXSize * nYSize;
1478 const size_t nGlobalSize = static_cast<size_t>(nGlobalBigSize);
1479 #if SIZEOF_VOIDP == 4
1480 if( static_cast<GUIntBig>(nGlobalSize) != nGlobalBigSize )
1481 {
1482 CPLError( CE_Failure, CPLE_OutOfMemory,
1483 "Cannot allocate " CPL_FRMT_GUIB " bytes on this platform.",
1484 nGlobalBigSize );
1485 return nullptr;
1486 }
1487 #endif
1488
1489 std::vector<GByte*> apbyBandData;
1490 bool bAllocOK = true;
1491
1492 if( bPixelInterleaved )
1493 {
1494 apbyBandData.push_back(
1495 reinterpret_cast<GByte *>( VSI_CALLOC_VERBOSE( 1, nGlobalSize ) ) );
1496
1497 if( apbyBandData[0] == nullptr )
1498 bAllocOK = FALSE;
1499 else
1500 {
1501 for( int iBand = 1; iBand < nBands; iBand++ )
1502 apbyBandData.push_back( apbyBandData[0] + iBand * nWordSize );
1503 }
1504 }
1505 else
1506 {
1507 for( int iBand = 0; iBand < nBands; iBand++ )
1508 {
1509 apbyBandData.push_back(
1510 reinterpret_cast<GByte *>(
1511 VSI_CALLOC_VERBOSE(
1512 1,
1513 static_cast<size_t>(nWordSize) * nXSize * nYSize ) ) );
1514 if( apbyBandData[iBand] == nullptr )
1515 {
1516 bAllocOK = FALSE;
1517 break;
1518 }
1519 }
1520 }
1521
1522 if( !bAllocOK )
1523 {
1524 for( int iBand = 0;
1525 iBand < static_cast<int>( apbyBandData.size() );
1526 iBand++ )
1527 {
1528 if( apbyBandData[iBand] )
1529 VSIFree( apbyBandData[iBand] );
1530 }
1531 return nullptr;
1532 }
1533
1534 /* -------------------------------------------------------------------- */
1535 /* Create the new GTiffDataset object. */
1536 /* -------------------------------------------------------------------- */
1537 MEMDataset *poDS = new MEMDataset();
1538
1539 poDS->nRasterXSize = nXSize;
1540 poDS->nRasterYSize = nYSize;
1541 poDS->eAccess = GA_Update;
1542
1543 const char *pszPixelType = CSLFetchNameValue( papszOptions, "PIXELTYPE" );
1544 if( pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE") )
1545 poDS->SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
1546
1547 if( bPixelInterleaved )
1548 poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
1549
1550 /* -------------------------------------------------------------------- */
1551 /* Create band information objects. */
1552 /* -------------------------------------------------------------------- */
1553 for( int iBand = 0; iBand < nBands; iBand++ )
1554 {
1555 MEMRasterBand *poNewBand = nullptr;
1556
1557 if( bPixelInterleaved )
1558 poNewBand = new MEMRasterBand( poDS, iBand+1, apbyBandData[iBand],
1559 eType, nWordSize * nBands, 0,
1560 iBand == 0 );
1561 else
1562 poNewBand = new MEMRasterBand( poDS, iBand+1, apbyBandData[iBand],
1563 eType, 0, 0, TRUE );
1564
1565 poDS->SetBand( iBand+1, poNewBand );
1566 }
1567
1568 /* -------------------------------------------------------------------- */
1569 /* Try to return a regular handle on the file. */
1570 /* -------------------------------------------------------------------- */
1571 return poDS;
1572 }
1573
1574 /************************************************************************/
1575 /* MEMGroup */
1576 /************************************************************************/
1577
1578 class MEMGroup final: public GDALGroup
1579 {
1580 std::map<CPLString, std::shared_ptr<GDALGroup>> m_oMapGroups{};
1581 std::map<CPLString, std::shared_ptr<GDALMDArray>> m_oMapMDArrays{};
1582 std::map<CPLString, std::shared_ptr<GDALAttribute>> m_oMapAttributes{};
1583 std::map<CPLString, std::shared_ptr<GDALDimension>> m_oMapDimensions{};
1584
1585 public:
MEMGroup(const std::string & osParentName,const char * pszName)1586 MEMGroup(const std::string& osParentName, const char* pszName): GDALGroup(osParentName, pszName ? pszName : "") {}
1587
1588 std::vector<std::string> GetMDArrayNames(CSLConstList papszOptions) const override;
1589 std::shared_ptr<GDALMDArray> OpenMDArray(const std::string& osName,
1590 CSLConstList papszOptions) const override;
1591
1592 std::vector<std::string> GetGroupNames(CSLConstList papszOptions) const override;
1593 std::shared_ptr<GDALGroup> OpenGroup(const std::string& osName,
1594 CSLConstList papszOptions) const override;
1595
1596 std::shared_ptr<GDALGroup> CreateGroup(const std::string& osName,
1597 CSLConstList papszOptions) override;
1598
1599 std::shared_ptr<GDALDimension> CreateDimension(const std::string&,
1600 const std::string&,
1601 const std::string&,
1602 GUInt64,
1603 CSLConstList papszOptions) override;
1604
1605 std::shared_ptr<GDALMDArray> CreateMDArray(const std::string& osName,
1606 const std::vector<std::shared_ptr<GDALDimension>>& aoDimensions,
1607 const GDALExtendedDataType& oDataType,
1608 CSLConstList papszOptions) override;
1609
1610 std::shared_ptr<GDALAttribute> GetAttribute(const std::string& osName) const override;
1611
1612 std::vector<std::shared_ptr<GDALAttribute>> GetAttributes(CSLConstList papszOptions) const override;
1613
1614 std::vector<std::shared_ptr<GDALDimension>> GetDimensions(CSLConstList papszOptions) const override;
1615
1616 std::shared_ptr<GDALAttribute> CreateAttribute(
1617 const std::string& osName,
1618 const std::vector<GUInt64>& anDimensions,
1619 const GDALExtendedDataType& oDataType,
1620 CSLConstList papszOptions) override;
1621 };
1622
1623 /************************************************************************/
1624 /* MEMAbstractMDArray */
1625 /************************************************************************/
1626
1627 class MEMAbstractMDArray: virtual public GDALAbstractMDArray
1628 {
1629 std::vector<std::shared_ptr<GDALDimension>> m_aoDims;
1630 size_t m_nTotalSize = 0;
1631 GByte* m_pabyArray{};
1632 bool m_bOwnArray = false;
1633 std::vector<GPtrDiff_t> m_anStrides{};
1634
1635 struct StackReadWrite
1636 {
1637 size_t nIters = 0;
1638 const GByte* src_ptr = nullptr;
1639 GByte* dst_ptr = nullptr;
1640 GPtrDiff_t src_inc_offset = 0;
1641 GPtrDiff_t dst_inc_offset = 0;
1642 };
1643
1644 void ReadWrite(bool bIsWrite,
1645 const size_t* count,
1646 std::vector<StackReadWrite>& stack,
1647 const GDALExtendedDataType& srcType,
1648 const GDALExtendedDataType& dstType) const;
1649
1650 protected:
1651 GDALExtendedDataType m_oType;
1652
1653 bool IRead(const GUInt64* arrayStartIdx, // array of size GetDimensionCount()
1654 const size_t* count, // array of size GetDimensionCount()
1655 const GInt64* arrayStep, // step in elements
1656 const GPtrDiff_t* bufferStride, // stride in elements
1657 const GDALExtendedDataType& bufferDataType,
1658 void* pDstBuffer) const override;
1659
1660 bool IWrite(const GUInt64* arrayStartIdx, // array of size GetDimensionCount()
1661 const size_t* count, // array of size GetDimensionCount()
1662 const GInt64* arrayStep, // step in elements
1663 const GPtrDiff_t* bufferStride, // stride in elements
1664 const GDALExtendedDataType& bufferDataType,
1665 const void* pSrcBuffer) override;
1666
1667 public:
1668 MEMAbstractMDArray(const std::string& osParentName,
1669 const std::string& osName,
1670 const std::vector<std::shared_ptr<GDALDimension>>& aoDimensions,
1671 const GDALExtendedDataType& oType);
1672 ~MEMAbstractMDArray();
1673
GetDimensions() const1674 const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_aoDims; }
1675
GetDataType() const1676 const GDALExtendedDataType& GetDataType() const override { return m_oType; }
1677
1678 bool Init(GByte* pData = nullptr,
1679 const std::vector<GPtrDiff_t>& anStrides = std::vector<GPtrDiff_t>());
1680 };
1681
1682 /************************************************************************/
1683 /* MEMMDArray */
1684 /************************************************************************/
1685
1686 #ifdef _MSC_VER
1687 #pragma warning (push)
1688 #pragma warning (disable:4250) // warning C4250: 'MEMMDArray': inherits 'MEMAbstractMDArray::MEMAbstractMDArray::IRead' via dominance
1689 #endif //_MSC_VER
1690
1691 class MEMMDArray final: public MEMAbstractMDArray, public GDALMDArray
1692 {
1693 std::map<CPLString, std::shared_ptr<GDALAttribute>> m_oMapAttributes{};
1694 std::string m_osUnit{};
1695 std::shared_ptr<OGRSpatialReference> m_poSRS{};
1696 GByte* m_pabyNoData = nullptr;
1697 double m_dfScale = 1.0;
1698 double m_dfOffset = 0.0;
1699 bool m_bHasScale = false;
1700 bool m_bHasOffset = false;
1701 GDALDataType m_eOffsetStorageType = GDT_Unknown;
1702 GDALDataType m_eScaleStorageType = GDT_Unknown;
1703
1704 protected:
1705 MEMMDArray(const std::string& osParentName,
1706 const std::string& osName,
1707 const std::vector<std::shared_ptr<GDALDimension>>& aoDimensions,
1708 const GDALExtendedDataType& oType);
1709
1710 public:
Create(const std::string & osParentName,const std::string & osName,const std::vector<std::shared_ptr<GDALDimension>> & aoDimensions,const GDALExtendedDataType & oType)1711 static std::shared_ptr<MEMMDArray> Create(const std::string& osParentName,
1712 const std::string& osName,
1713 const std::vector<std::shared_ptr<GDALDimension>>& aoDimensions,
1714 const GDALExtendedDataType& oType)
1715 {
1716 auto array(std::shared_ptr<MEMMDArray>(
1717 new MEMMDArray(osParentName, osName, aoDimensions, oType)));
1718 array->SetSelf(array);
1719 return array;
1720 }
1721 ~MEMMDArray();
1722
IsWritable() const1723 bool IsWritable() const override { return true; }
1724
1725 std::shared_ptr<GDALAttribute> GetAttribute(const std::string& osName) const override;
1726
1727 std::vector<std::shared_ptr<GDALAttribute>> GetAttributes(CSLConstList papszOptions) const override;
1728
1729 std::shared_ptr<GDALAttribute> CreateAttribute(
1730 const std::string& osName,
1731 const std::vector<GUInt64>& anDimensions,
1732 const GDALExtendedDataType& oDataType,
1733 CSLConstList papszOptions) override;
1734
GetUnit() const1735 const std::string& GetUnit() const override { return m_osUnit; }
1736
SetUnit(const std::string & osUnit)1737 bool SetUnit(const std::string& osUnit) override {
1738 m_osUnit = osUnit; return true; }
1739
SetSpatialRef(const OGRSpatialReference * poSRS)1740 bool SetSpatialRef(const OGRSpatialReference* poSRS) override {
1741 m_poSRS.reset(poSRS ? poSRS->Clone() : nullptr); return true; }
1742
GetSpatialRef() const1743 std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override { return m_poSRS; }
1744
1745 const void* GetRawNoDataValue() const override;
1746
1747 bool SetRawNoDataValue(const void*) override;
1748
GetOffset(bool * pbHasOffset,GDALDataType * peStorageType) const1749 double GetOffset(bool* pbHasOffset, GDALDataType* peStorageType) const override
1750 {
1751 if( pbHasOffset) *pbHasOffset = m_bHasOffset;
1752 if( peStorageType ) *peStorageType = m_eOffsetStorageType;
1753 return m_dfOffset;
1754 }
1755
GetScale(bool * pbHasScale,GDALDataType * peStorageType) const1756 double GetScale(bool* pbHasScale, GDALDataType* peStorageType) const override
1757 {
1758 if( pbHasScale) *pbHasScale = m_bHasScale;
1759 if( peStorageType ) *peStorageType = m_eScaleStorageType;
1760 return m_dfScale;
1761 }
1762
SetOffset(double dfOffset,GDALDataType eStorageType)1763 bool SetOffset(double dfOffset, GDALDataType eStorageType) override
1764 { m_bHasOffset = true; m_dfOffset = dfOffset; m_eOffsetStorageType = eStorageType; return true; }
1765
SetScale(double dfScale,GDALDataType eStorageType)1766 bool SetScale(double dfScale, GDALDataType eStorageType) override
1767 { m_bHasScale = true; m_dfScale = dfScale; m_eScaleStorageType = eStorageType; return true; }
1768 };
1769
1770 /************************************************************************/
1771 /* MEMAttribute */
1772 /************************************************************************/
1773
1774 class MEMAttribute final: public MEMAbstractMDArray, public GDALAttribute
1775 {
1776 protected:
1777 MEMAttribute(const std::string& osParentName,
1778 const std::string& osName,
1779 const std::vector<GUInt64>& anDimensions,
1780 const GDALExtendedDataType& oType);
1781 public:
Create(const std::string & osParentName,const std::string & osName,const std::vector<GUInt64> & anDimensions,const GDALExtendedDataType & oType)1782 static std::shared_ptr<MEMAttribute> Create(const std::string& osParentName,
1783 const std::string& osName,
1784 const std::vector<GUInt64>& anDimensions,
1785 const GDALExtendedDataType& oType)
1786 {
1787 auto attr(std::shared_ptr<MEMAttribute>(
1788 new MEMAttribute(osParentName, osName, anDimensions, oType)));
1789 attr->SetSelf(attr);
1790 return attr;
1791 }
1792 };
1793
1794 #ifdef _MSC_VER
1795 #pragma warning (pop)
1796 #endif //_MSC_VER
1797
1798 /************************************************************************/
1799 /* MEMDimension */
1800 /************************************************************************/
1801
1802 class MEMDimension final: public GDALDimension
1803 {
1804 std::weak_ptr<GDALMDArray> m_poIndexingVariable{};
1805
1806 public:
1807 MEMDimension(const std::string& osParentName,
1808 const std::string& osName,
1809 const std::string& osType,
1810 const std::string& osDirection,
1811 GUInt64 nSize);
1812
GetIndexingVariable() const1813 std::shared_ptr<GDALMDArray> GetIndexingVariable() const override { return m_poIndexingVariable.lock(); }
1814
1815 bool SetIndexingVariable(std::shared_ptr<GDALMDArray> poIndexingVariable) override;
1816 };
1817
1818 /************************************************************************/
1819 /* GetMDArrayNames() */
1820 /************************************************************************/
1821
GetMDArrayNames(CSLConstList) const1822 std::vector<std::string> MEMGroup::GetMDArrayNames(CSLConstList) const
1823 {
1824 std::vector<std::string> names;
1825 for( const auto& iter: m_oMapMDArrays )
1826 names.push_back(iter.first);
1827 return names;
1828 }
1829
1830 /************************************************************************/
1831 /* OpenMDArray() */
1832 /************************************************************************/
1833
OpenMDArray(const std::string & osName,CSLConstList) const1834 std::shared_ptr<GDALMDArray> MEMGroup::OpenMDArray(const std::string& osName,
1835 CSLConstList) const
1836 {
1837 auto oIter = m_oMapMDArrays.find(osName);
1838 if( oIter != m_oMapMDArrays.end() )
1839 return oIter->second;
1840 return nullptr;
1841 }
1842
1843 /************************************************************************/
1844 /* GetGroupNames() */
1845 /************************************************************************/
1846
GetGroupNames(CSLConstList) const1847 std::vector<std::string> MEMGroup::GetGroupNames(CSLConstList) const
1848 {
1849 std::vector<std::string> names;
1850 for( const auto& iter: m_oMapGroups )
1851 names.push_back(iter.first);
1852 return names;
1853 }
1854
1855 /************************************************************************/
1856 /* OpenGroup() */
1857 /************************************************************************/
1858
OpenGroup(const std::string & osName,CSLConstList) const1859 std::shared_ptr<GDALGroup> MEMGroup::OpenGroup(const std::string& osName,
1860 CSLConstList) const
1861 {
1862 auto oIter = m_oMapGroups.find(osName);
1863 if( oIter != m_oMapGroups.end() )
1864 return oIter->second;
1865 return nullptr;
1866 }
1867
1868 /************************************************************************/
1869 /* CreateGroup() */
1870 /************************************************************************/
1871
CreateGroup(const std::string & osName,CSLConstList)1872 std::shared_ptr<GDALGroup> MEMGroup::CreateGroup(const std::string& osName,
1873 CSLConstList /*papszOptions*/)
1874 {
1875 if( osName.empty() )
1876 {
1877 CPLError(CE_Failure, CPLE_NotSupported,
1878 "Empty group name not supported");
1879 return nullptr;
1880 }
1881 if( m_oMapGroups.find(osName) != m_oMapGroups.end() )
1882 {
1883 CPLError(CE_Failure, CPLE_AppDefined,
1884 "A group with same name already exists");
1885 return nullptr;
1886 }
1887 auto newGroup(std::make_shared<MEMGroup>(GetFullName(), osName.c_str()));
1888 m_oMapGroups[osName] = newGroup;
1889 return newGroup;
1890 }
1891
1892 /************************************************************************/
1893 /* CreateMDArray() */
1894 /************************************************************************/
1895
CreateMDArray(const std::string & osName,const std::vector<std::shared_ptr<GDALDimension>> & aoDimensions,const GDALExtendedDataType & oType,CSLConstList papszOptions)1896 std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray(const std::string& osName,
1897 const std::vector<std::shared_ptr<GDALDimension>>& aoDimensions,
1898 const GDALExtendedDataType& oType,
1899 CSLConstList papszOptions)
1900 {
1901 if( osName.empty() )
1902 {
1903 CPLError(CE_Failure, CPLE_NotSupported,
1904 "Empty array name not supported");
1905 return nullptr;
1906 }
1907 if( m_oMapMDArrays.find(osName) != m_oMapMDArrays.end() )
1908 {
1909 CPLError(CE_Failure, CPLE_AppDefined,
1910 "An array with same name already exists");
1911 return nullptr;
1912 }
1913 auto newArray(MEMMDArray::Create(GetFullName(), osName, aoDimensions, oType));
1914
1915 // Used by NUMPYMultiDimensionalDataset
1916 const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER");
1917 GByte* pData = nullptr;
1918 std::vector<GPtrDiff_t> anStrides;
1919 if( pszDataPointer )
1920 {
1921 pData = reinterpret_cast<GByte *>(
1922 CPLScanPointer( pszDataPointer,
1923 static_cast<int>(strlen(pszDataPointer)) ) );
1924 const char* pszStrides = CSLFetchNameValue(papszOptions, "STRIDES");
1925 if( pszStrides )
1926 {
1927 CPLStringList aosStrides(CSLTokenizeString2(pszStrides, ",", 0));
1928 if( static_cast<size_t>(aosStrides.size()) != aoDimensions.size() )
1929 {
1930 CPLError(CE_Failure, CPLE_AppDefined,
1931 "Invalid number of strides");
1932 return nullptr;
1933 }
1934 for( int i = 0; i < aosStrides.size(); i++ )
1935 {
1936 const auto nStride = CPLAtoGIntBig(aosStrides[i]);
1937 anStrides.push_back(static_cast<GPtrDiff_t>(nStride));
1938 }
1939 }
1940 }
1941 if( !newArray->Init(pData, anStrides) )
1942 return nullptr;
1943 m_oMapMDArrays[osName] = newArray;
1944 return newArray;
1945 }
1946
1947 /************************************************************************/
1948 /* GetAttribute() */
1949 /************************************************************************/
1950
GetAttribute(const std::string & osName) const1951 std::shared_ptr<GDALAttribute> MEMGroup::GetAttribute(const std::string& osName) const
1952 {
1953 auto oIter = m_oMapAttributes.find(osName);
1954 if( oIter != m_oMapAttributes.end() )
1955 return oIter->second;
1956 return nullptr;
1957 }
1958
1959 /************************************************************************/
1960 /* GetAttributes() */
1961 /************************************************************************/
1962
GetAttributes(CSLConstList) const1963 std::vector<std::shared_ptr<GDALAttribute>> MEMGroup::GetAttributes(CSLConstList) const
1964 {
1965 std::vector<std::shared_ptr<GDALAttribute>> oRes;
1966 for( const auto& oIter: m_oMapAttributes )
1967 {
1968 oRes.push_back(oIter.second);
1969 }
1970 return oRes;
1971 }
1972
1973 /************************************************************************/
1974 /* GetDimensions() */
1975 /************************************************************************/
1976
GetDimensions(CSLConstList) const1977 std::vector<std::shared_ptr<GDALDimension>> MEMGroup::GetDimensions(CSLConstList) const
1978 {
1979 std::vector<std::shared_ptr<GDALDimension>> oRes;
1980 for( const auto& oIter: m_oMapDimensions )
1981 {
1982 oRes.push_back(oIter.second);
1983 }
1984 return oRes;
1985 }
1986
1987 /************************************************************************/
1988 /* CreateAttribute() */
1989 /************************************************************************/
1990
CreateAttribute(const std::string & osName,const std::vector<GUInt64> & anDimensions,const GDALExtendedDataType & oDataType,CSLConstList)1991 std::shared_ptr<GDALAttribute> MEMGroup::CreateAttribute(
1992 const std::string& osName,
1993 const std::vector<GUInt64>& anDimensions,
1994 const GDALExtendedDataType& oDataType,
1995 CSLConstList)
1996 {
1997 if( osName.empty() )
1998 {
1999 CPLError(CE_Failure, CPLE_NotSupported,
2000 "Empty attribute name not supported");
2001 return nullptr;
2002 }
2003 if( m_oMapAttributes.find(osName) != m_oMapAttributes.end() )
2004 {
2005 CPLError(CE_Failure, CPLE_AppDefined,
2006 "An attribute with same name already exists");
2007 return nullptr;
2008 }
2009 auto newAttr(MEMAttribute::Create(
2010 (GetFullName() == "/" ? "/" : GetFullName() + "/") + "_GLOBAL_",
2011 osName, anDimensions, oDataType));
2012 if( !newAttr->Init() )
2013 return nullptr;
2014 m_oMapAttributes[osName] = newAttr;
2015 return newAttr;
2016 }
2017
2018 /************************************************************************/
2019 /* MEMAbstractMDArray() */
2020 /************************************************************************/
2021
MEMAbstractMDArray(const std::string & osParentName,const std::string & osName,const std::vector<std::shared_ptr<GDALDimension>> & aoDimensions,const GDALExtendedDataType & oType)2022 MEMAbstractMDArray::MEMAbstractMDArray(const std::string& osParentName,
2023 const std::string& osName,
2024 const std::vector<std::shared_ptr<GDALDimension>>& aoDimensions,
2025 const GDALExtendedDataType& oType):
2026 GDALAbstractMDArray(osParentName, osName),
2027 m_aoDims(aoDimensions),
2028 m_oType(oType)
2029 {
2030 }
2031
2032 /************************************************************************/
2033 /* ~MEMAbstractMDArray() */
2034 /************************************************************************/
2035
~MEMAbstractMDArray()2036 MEMAbstractMDArray::~MEMAbstractMDArray()
2037 {
2038 if( m_bOwnArray )
2039 {
2040 if( m_oType.NeedsFreeDynamicMemory() )
2041 {
2042 GByte* pabyPtr = m_pabyArray;
2043 GByte* pabyEnd = m_pabyArray + m_nTotalSize;
2044 const auto nDTSize(m_oType.GetSize());
2045 while(pabyPtr < pabyEnd)
2046 {
2047 m_oType.FreeDynamicMemory(pabyPtr);
2048 pabyPtr += nDTSize;
2049 }
2050 }
2051 VSIFree(m_pabyArray);
2052 }
2053 }
2054
2055 /************************************************************************/
2056 /* Init() */
2057 /************************************************************************/
2058
Init(GByte * pData,const std::vector<GPtrDiff_t> & anStrides)2059 bool MEMAbstractMDArray::Init(GByte* pData,
2060 const std::vector<GPtrDiff_t>& anStrides)
2061 {
2062 GUInt64 nTotalSize = m_oType.GetSize();
2063 if( !m_aoDims.empty() )
2064 {
2065 if( anStrides.empty() )
2066 {
2067 m_anStrides.resize(m_aoDims.size());
2068 }
2069 else
2070 {
2071 CPLAssert( anStrides.size() == m_aoDims.size() );
2072 m_anStrides = anStrides;
2073 }
2074
2075 // To compute strides we must proceed from the fastest varying dimension
2076 // (the last one), and then reverse the result
2077 for( size_t i = m_aoDims.size(); i != 0; )
2078 {
2079 --i;
2080 const auto& poDim = m_aoDims[i];
2081 auto nDimSize = poDim->GetSize();
2082 if( nDimSize != 0 && nTotalSize > std::numeric_limits<GUInt64>::max() / nDimSize )
2083 {
2084 CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
2085 return false;
2086 }
2087 auto nNewSize = nTotalSize * nDimSize;
2088 if( anStrides.empty() )
2089 m_anStrides[i] = static_cast<size_t>(nTotalSize);
2090 nTotalSize = nNewSize;
2091 }
2092 }
2093
2094 // We restrict the size of the allocation so that all elements can be
2095 // indexed by GPtrDiff_t
2096 if( nTotalSize > static_cast<size_t>(
2097 std::numeric_limits<GPtrDiff_t>::max()) )
2098 {
2099 CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation");
2100 return false;
2101 }
2102 m_nTotalSize = static_cast<size_t>(nTotalSize);
2103 if( pData )
2104 {
2105 m_pabyArray = pData;
2106 }
2107 else
2108 {
2109 m_pabyArray = static_cast<GByte*>(VSI_CALLOC_VERBOSE(1, m_nTotalSize));
2110 m_bOwnArray = true;
2111 }
2112 return m_pabyArray != nullptr;
2113 }
2114
2115 /************************************************************************/
2116 /* FastCopy() */
2117 /************************************************************************/
2118
FastCopy(size_t nIters,GByte * dstPtr,const GByte * srcPtr,GPtrDiff_t dst_inc_offset,GPtrDiff_t src_inc_offset)2119 template<int N> inline static void FastCopy(size_t nIters,
2120 GByte* dstPtr,
2121 const GByte* srcPtr,
2122 GPtrDiff_t dst_inc_offset,
2123 GPtrDiff_t src_inc_offset)
2124 {
2125 if( nIters >= 8 )
2126 {
2127 #define COPY_ELT(i) memcpy(dstPtr + (i) * dst_inc_offset, srcPtr + (i) * src_inc_offset, N)
2128 while(true)
2129 {
2130 COPY_ELT(0);
2131 COPY_ELT(1);
2132 COPY_ELT(2);
2133 COPY_ELT(3);
2134 COPY_ELT(4);
2135 COPY_ELT(5);
2136 COPY_ELT(6);
2137 COPY_ELT(7);
2138 nIters -= 8;
2139 srcPtr += 8 * src_inc_offset;
2140 dstPtr += 8 * dst_inc_offset;
2141 if( nIters < 8 )
2142 break;
2143 }
2144 if( nIters == 0 )
2145 return;
2146 }
2147 while(true)
2148 {
2149 memcpy(dstPtr, srcPtr, N);
2150 if( (--nIters) == 0 )
2151 break;
2152 srcPtr += src_inc_offset;
2153 dstPtr += dst_inc_offset;
2154 }
2155 }
2156
2157 /************************************************************************/
2158 /* ReadWrite() */
2159 /************************************************************************/
2160
ReadWrite(bool bIsWrite,const size_t * count,std::vector<StackReadWrite> & stack,const GDALExtendedDataType & srcType,const GDALExtendedDataType & dstType) const2161 void MEMAbstractMDArray::ReadWrite(bool bIsWrite,
2162 const size_t* count,
2163 std::vector<StackReadWrite>& stack,
2164 const GDALExtendedDataType& srcType,
2165 const GDALExtendedDataType& dstType) const
2166 {
2167 const auto nDims = m_aoDims.size();
2168 const auto nDimsMinus1 = nDims - 1;
2169 const bool bSameNumericDT =
2170 srcType.GetClass() == GEDTC_NUMERIC &&
2171 dstType.GetClass() == GEDTC_NUMERIC &&
2172 srcType.GetNumericDataType() == dstType.GetNumericDataType();
2173 const auto nSameDTSize = bSameNumericDT ? srcType.GetSize() : 0;
2174 const bool bCanUseMemcpyLastDim =
2175 bSameNumericDT &&
2176 stack[nDimsMinus1].src_inc_offset == static_cast<GPtrDiff_t>(nSameDTSize) &&
2177 stack[nDimsMinus1].dst_inc_offset == static_cast<GPtrDiff_t>(nSameDTSize);
2178 const size_t nCopySizeLastDim =
2179 bCanUseMemcpyLastDim ? nSameDTSize * count[nDimsMinus1] : 0;
2180 const bool bNeedsFreeDynamicMemory = bIsWrite && dstType.NeedsFreeDynamicMemory();
2181
2182 auto lambdaLastDim = [&](size_t idxPtr)
2183 {
2184 auto srcPtr = stack[idxPtr].src_ptr;
2185 auto dstPtr = stack[idxPtr].dst_ptr;
2186 if( nCopySizeLastDim )
2187 {
2188 memcpy(dstPtr, srcPtr, nCopySizeLastDim);
2189 }
2190 else
2191 {
2192 size_t nIters = count[nDimsMinus1];
2193 const auto dst_inc_offset = stack[nDimsMinus1].dst_inc_offset;
2194 const auto src_inc_offset = stack[nDimsMinus1].src_inc_offset;
2195 if( bSameNumericDT )
2196 {
2197 if( nSameDTSize == 1 )
2198 {
2199 FastCopy<1>(nIters, dstPtr, srcPtr,
2200 dst_inc_offset, src_inc_offset);
2201 return;
2202 }
2203 if( nSameDTSize == 2 )
2204 {
2205 FastCopy<2>(nIters, dstPtr, srcPtr,
2206 dst_inc_offset, src_inc_offset);
2207 return;
2208 }
2209 if( nSameDTSize == 4 )
2210 {
2211 FastCopy<4>(nIters, dstPtr, srcPtr,
2212 dst_inc_offset, src_inc_offset);
2213 return;
2214 }
2215 if( nSameDTSize == 8 )
2216 {
2217 FastCopy<8>(nIters, dstPtr, srcPtr,
2218 dst_inc_offset, src_inc_offset);
2219 return;
2220 }
2221 if( nSameDTSize == 16 )
2222 {
2223 FastCopy<16>(nIters, dstPtr, srcPtr,
2224 dst_inc_offset, src_inc_offset);
2225 return;
2226 }
2227 CPLAssert(false);
2228 }
2229
2230 while(true)
2231 {
2232 if( bNeedsFreeDynamicMemory )
2233 {
2234 dstType.FreeDynamicMemory(dstPtr);
2235 }
2236 GDALExtendedDataType::CopyValue(srcPtr, srcType, dstPtr, dstType);
2237 if( (--nIters) == 0 )
2238 break;
2239 srcPtr += src_inc_offset;
2240 dstPtr += dst_inc_offset;
2241 }
2242 }
2243 };
2244
2245 if( nDims == 1 )
2246 {
2247 lambdaLastDim(0);
2248 }
2249 else if( nDims == 2 )
2250 {
2251 auto nIters = count[0];
2252 while(true)
2253 {
2254 lambdaLastDim(0);
2255 if( (--nIters) == 0 )
2256 break;
2257 stack[0].src_ptr += stack[0].src_inc_offset;
2258 stack[0].dst_ptr += stack[0].dst_inc_offset;
2259 }
2260 }
2261 else if( nDims == 3 )
2262 {
2263 stack[0].nIters = count[0];
2264 while(true)
2265 {
2266 stack[1].src_ptr = stack[0].src_ptr;
2267 stack[1].dst_ptr = stack[0].dst_ptr;
2268 auto nIters = count[1];
2269 while(true)
2270 {
2271 lambdaLastDim(1);
2272 if( (--nIters) == 0 )
2273 break;
2274 stack[1].src_ptr += stack[1].src_inc_offset;
2275 stack[1].dst_ptr += stack[1].dst_inc_offset;
2276 }
2277 if( (--stack[0].nIters) == 0 )
2278 break;
2279 stack[0].src_ptr += stack[0].src_inc_offset;
2280 stack[0].dst_ptr += stack[0].dst_inc_offset;
2281 }
2282 }
2283 else
2284 {
2285 // Implementation valid for nDims >= 3
2286
2287 size_t dimIdx = 0;
2288 // Non-recursive implementation. Hence the gotos
2289 // It might be possible to rewrite this without gotos, but I find they
2290 // make it clearer to understand the recursive nature of the code
2291 lbl_next_depth:
2292 if( dimIdx == nDimsMinus1 - 1 )
2293 {
2294 auto nIters = count[dimIdx];
2295 while(true)
2296 {
2297 lambdaLastDim(dimIdx);
2298 if( (--nIters) == 0 )
2299 break;
2300 stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
2301 stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
2302 }
2303 // If there was a test if( dimIdx > 0 ), that would be valid for nDims == 2
2304 goto lbl_return_to_caller;
2305 }
2306 else
2307 {
2308 stack[dimIdx].nIters = count[dimIdx];
2309 while(true)
2310 {
2311 dimIdx ++;
2312 stack[dimIdx].src_ptr = stack[dimIdx-1].src_ptr;
2313 stack[dimIdx].dst_ptr = stack[dimIdx-1].dst_ptr;
2314 goto lbl_next_depth;
2315 lbl_return_to_caller:
2316 dimIdx --;
2317 if( (--stack[dimIdx].nIters) == 0 )
2318 break;
2319 stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
2320 stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
2321 }
2322 if( dimIdx > 0 )
2323 goto lbl_return_to_caller;
2324 }
2325 }
2326 }
2327
2328 /************************************************************************/
2329 /* IRead() */
2330 /************************************************************************/
2331
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const2332 bool MEMAbstractMDArray::IRead(const GUInt64* arrayStartIdx,
2333 const size_t* count,
2334 const GInt64* arrayStep,
2335 const GPtrDiff_t* bufferStride,
2336 const GDALExtendedDataType& bufferDataType,
2337 void* pDstBuffer) const
2338 {
2339 const auto nDims = m_aoDims.size();
2340 if( nDims == 0 )
2341 {
2342 GDALExtendedDataType::CopyValue(m_pabyArray, m_oType, pDstBuffer, bufferDataType);
2343 return true;
2344 }
2345 std::vector<StackReadWrite> stack(nDims);
2346 const auto nBufferDTSize = bufferDataType.GetSize();
2347 GPtrDiff_t startSrcOffset = 0;
2348 for( size_t i = 0; i < nDims; i++ )
2349 {
2350 startSrcOffset += static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]);
2351 stack[i].src_inc_offset = static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]);
2352 stack[i].dst_inc_offset = static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize);
2353 }
2354 stack[0].src_ptr = m_pabyArray + startSrcOffset;
2355 stack[0].dst_ptr = static_cast<GByte*>(pDstBuffer);
2356
2357 ReadWrite(false, count, stack, m_oType, bufferDataType);
2358 return true;
2359 }
2360
2361 /************************************************************************/
2362 /* IWrite() */
2363 /************************************************************************/
2364
IWrite(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,const void * pSrcBuffer)2365 bool MEMAbstractMDArray::IWrite(const GUInt64* arrayStartIdx,
2366 const size_t* count,
2367 const GInt64* arrayStep,
2368 const GPtrDiff_t* bufferStride,
2369 const GDALExtendedDataType& bufferDataType,
2370 const void* pSrcBuffer)
2371 {
2372 const auto nDims = m_aoDims.size();
2373 if( nDims == 0 )
2374 {
2375 m_oType.FreeDynamicMemory(m_pabyArray);
2376 GDALExtendedDataType::CopyValue(pSrcBuffer, bufferDataType, m_pabyArray, m_oType);
2377 return true;
2378 }
2379 std::vector<StackReadWrite> stack(nDims);
2380 const auto nBufferDTSize = bufferDataType.GetSize();
2381 GPtrDiff_t startDstOffset = 0;
2382 for( size_t i = 0; i < nDims; i++ )
2383 {
2384 startDstOffset += static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]);
2385 stack[i].dst_inc_offset = static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]);
2386 stack[i].src_inc_offset = static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize);
2387 }
2388
2389 stack[0].dst_ptr = m_pabyArray + startDstOffset;
2390 stack[0].src_ptr = static_cast<const GByte*>(pSrcBuffer);
2391
2392 ReadWrite(true, count, stack, bufferDataType, m_oType);
2393 return true;
2394 }
2395
2396 /************************************************************************/
2397 /* MEMMDArray() */
2398 /************************************************************************/
2399
MEMMDArray(const std::string & osParentName,const std::string & osName,const std::vector<std::shared_ptr<GDALDimension>> & aoDimensions,const GDALExtendedDataType & oType)2400 MEMMDArray::MEMMDArray(const std::string& osParentName,
2401 const std::string& osName,
2402 const std::vector<std::shared_ptr<GDALDimension>>& aoDimensions,
2403 const GDALExtendedDataType& oType):
2404 GDALAbstractMDArray(osParentName, osName),
2405 MEMAbstractMDArray(osParentName, osName, aoDimensions, oType),
2406 GDALMDArray(osParentName, osName)
2407 {
2408 }
2409
2410 /************************************************************************/
2411 /* ~MEMMDArray() */
2412 /************************************************************************/
2413
~MEMMDArray()2414 MEMMDArray::~MEMMDArray()
2415 {
2416 if( m_pabyNoData )
2417 {
2418 m_oType.FreeDynamicMemory(&m_pabyNoData[0]);
2419 CPLFree(m_pabyNoData);
2420 }
2421 }
2422
2423 /************************************************************************/
2424 /* GetRawNoDataValue() */
2425 /************************************************************************/
2426
GetRawNoDataValue() const2427 const void* MEMMDArray::GetRawNoDataValue() const
2428 {
2429 return m_pabyNoData;
2430 }
2431
2432 /************************************************************************/
2433 /* SetRawNoDataValue() */
2434 /************************************************************************/
2435
SetRawNoDataValue(const void * pNoData)2436 bool MEMMDArray::SetRawNoDataValue(const void* pNoData)
2437 {
2438 if( m_pabyNoData )
2439 {
2440 m_oType.FreeDynamicMemory(&m_pabyNoData[0]);
2441 }
2442
2443 if( pNoData == nullptr )
2444 {
2445 CPLFree(m_pabyNoData);
2446 m_pabyNoData = nullptr;
2447 }
2448 else
2449 {
2450 const auto nSize = m_oType.GetSize();
2451 if( m_pabyNoData == nullptr )
2452 {
2453 m_pabyNoData = static_cast<GByte*>(CPLMalloc(nSize));
2454 }
2455 memset(m_pabyNoData, 0, nSize);
2456 GDALExtendedDataType::CopyValue( pNoData, m_oType, m_pabyNoData, m_oType );
2457 }
2458 return true;
2459 }
2460
2461 /************************************************************************/
2462 /* GetAttribute() */
2463 /************************************************************************/
2464
GetAttribute(const std::string & osName) const2465 std::shared_ptr<GDALAttribute> MEMMDArray::GetAttribute(const std::string& osName) const
2466 {
2467 auto oIter = m_oMapAttributes.find(osName);
2468 if( oIter != m_oMapAttributes.end() )
2469 return oIter->second;
2470 return nullptr;
2471 }
2472
2473 /************************************************************************/
2474 /* GetAttributes() */
2475 /************************************************************************/
2476
GetAttributes(CSLConstList) const2477 std::vector<std::shared_ptr<GDALAttribute>> MEMMDArray::GetAttributes(CSLConstList) const
2478 {
2479 std::vector<std::shared_ptr<GDALAttribute>> oRes;
2480 for( const auto& oIter: m_oMapAttributes )
2481 {
2482 oRes.push_back(oIter.second);
2483 }
2484 return oRes;
2485 }
2486
2487 /************************************************************************/
2488 /* CreateAttribute() */
2489 /************************************************************************/
2490
CreateAttribute(const std::string & osName,const std::vector<GUInt64> & anDimensions,const GDALExtendedDataType & oDataType,CSLConstList)2491 std::shared_ptr<GDALAttribute> MEMMDArray::CreateAttribute(
2492 const std::string& osName,
2493 const std::vector<GUInt64>& anDimensions,
2494 const GDALExtendedDataType& oDataType,
2495 CSLConstList)
2496 {
2497 if( osName.empty() )
2498 {
2499 CPLError(CE_Failure, CPLE_NotSupported,
2500 "Empty attribute name not supported");
2501 return nullptr;
2502 }
2503 if( m_oMapAttributes.find(osName) != m_oMapAttributes.end() )
2504 {
2505 CPLError(CE_Failure, CPLE_AppDefined,
2506 "An attribute with same name already exists");
2507 return nullptr;
2508 }
2509 auto newAttr(MEMAttribute::Create(GetFullName(), osName, anDimensions, oDataType));
2510 if( !newAttr->Init() )
2511 return nullptr;
2512 m_oMapAttributes[osName] = newAttr;
2513 return newAttr;
2514 }
2515
2516 /************************************************************************/
2517 /* BuildDimensions() */
2518 /************************************************************************/
2519
BuildDimensions(const std::vector<GUInt64> & anDimensions)2520 static std::vector<std::shared_ptr<GDALDimension>> BuildDimensions(
2521 const std::vector<GUInt64>& anDimensions)
2522 {
2523 std::vector<std::shared_ptr<GDALDimension>> res;
2524 for( size_t i = 0; i < anDimensions.size(); i++ )
2525 {
2526 res.emplace_back(std::make_shared<MEMDimension>(
2527 std::string(), CPLSPrintf("dim%u", static_cast<unsigned>(i)),
2528 std::string(), std::string(), anDimensions[i]));
2529 }
2530 return res;
2531 }
2532
2533 /************************************************************************/
2534 /* MEMAttribute() */
2535 /************************************************************************/
2536
MEMAttribute(const std::string & osParentName,const std::string & osName,const std::vector<GUInt64> & anDimensions,const GDALExtendedDataType & oType)2537 MEMAttribute::MEMAttribute(const std::string& osParentName,
2538 const std::string& osName,
2539 const std::vector<GUInt64>& anDimensions,
2540 const GDALExtendedDataType& oType):
2541 GDALAbstractMDArray(osParentName, osName),
2542 MEMAbstractMDArray(osParentName, osName, BuildDimensions(anDimensions), oType),
2543 GDALAttribute(osParentName, osName)
2544 {
2545 }
2546
2547 /************************************************************************/
2548 /* MEMDimension() */
2549 /************************************************************************/
2550
MEMDimension(const std::string & osParentName,const std::string & osName,const std::string & osType,const std::string & osDirection,GUInt64 nSize)2551 MEMDimension::MEMDimension(const std::string& osParentName,
2552 const std::string& osName,
2553 const std::string& osType,
2554 const std::string& osDirection,
2555 GUInt64 nSize):
2556 GDALDimension(osParentName, osName, osType, osDirection, nSize)
2557 {
2558 }
2559
2560 /************************************************************************/
2561 /* SetIndexingVariable() */
2562 /************************************************************************/
2563
2564 // cppcheck-suppress passedByValue
SetIndexingVariable(std::shared_ptr<GDALMDArray> poIndexingVariable)2565 bool MEMDimension::SetIndexingVariable(std::shared_ptr<GDALMDArray> poIndexingVariable)
2566 {
2567 m_poIndexingVariable = poIndexingVariable;
2568 return true;
2569 }
2570
2571 /************************************************************************/
2572 /* CreateDimension() */
2573 /************************************************************************/
2574
CreateDimension(const std::string & osName,const std::string & osType,const std::string & osDirection,GUInt64 nSize,CSLConstList)2575 std::shared_ptr<GDALDimension> MEMGroup::CreateDimension(const std::string& osName,
2576 const std::string& osType,
2577 const std::string& osDirection,
2578 GUInt64 nSize,
2579 CSLConstList)
2580 {
2581 if( osName.empty() )
2582 {
2583 CPLError(CE_Failure, CPLE_NotSupported,
2584 "Empty dimension name not supported");
2585 return nullptr;
2586 }
2587 if( m_oMapDimensions.find(osName) != m_oMapDimensions.end() )
2588 {
2589 CPLError(CE_Failure, CPLE_AppDefined,
2590 "A dimension with same name already exists");
2591 return nullptr;
2592 }
2593 auto newDim(std::make_shared<MEMDimension>(GetFullName(), osName, osType, osDirection, nSize));
2594 m_oMapDimensions[osName] = newDim;
2595 return newDim;
2596 }
2597
2598 /************************************************************************/
2599 /* CreateMultiDimensional() */
2600 /************************************************************************/
2601
CreateMultiDimensional(const char * pszFilename,CSLConstList,CSLConstList)2602 GDALDataset * MEMDataset::CreateMultiDimensional( const char * pszFilename,
2603 CSLConstList /*papszRootGroupOptions*/,
2604 CSLConstList /*papszOptions*/ )
2605 {
2606 auto poDS = new MEMDataset();
2607
2608 poDS->SetDescription(pszFilename);
2609 poDS->m_poPrivate->m_poRootGroup.reset(new MEMGroup(std::string(), nullptr));
2610
2611 return poDS;
2612 }
2613
2614 /************************************************************************/
2615 /* GetRootGroup() */
2616 /************************************************************************/
2617
GetRootGroup() const2618 std::shared_ptr<GDALGroup> MEMDataset::GetRootGroup() const
2619 {
2620 return m_poPrivate->m_poRootGroup;
2621 }
2622
2623 /************************************************************************/
2624 /* MEMDatasetIdentify() */
2625 /************************************************************************/
2626
MEMDatasetIdentify(GDALOpenInfo * poOpenInfo)2627 static int MEMDatasetIdentify( GDALOpenInfo * poOpenInfo )
2628 {
2629 return (STARTS_WITH(poOpenInfo->pszFilename, "MEM:::") &&
2630 poOpenInfo->fpL == nullptr);
2631 }
2632
2633 /************************************************************************/
2634 /* MEMDatasetDelete() */
2635 /************************************************************************/
2636
MEMDatasetDelete(const char *)2637 static CPLErr MEMDatasetDelete( const char* /* fileName */)
2638 {
2639 /* Null implementation, so that people can Delete("MEM:::") */
2640 return CE_None;
2641 }
2642
2643 /************************************************************************/
2644 /* GDALRegister_MEM() */
2645 /************************************************************************/
2646
GDALRegister_MEM()2647 void GDALRegister_MEM()
2648
2649 {
2650 if( GDALGetDriverByName( "MEM" ) != nullptr )
2651 return;
2652
2653 GDALDriver *poDriver = new GDALDriver();
2654
2655 poDriver->SetDescription( "MEM" );
2656 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
2657 poDriver->SetMetadataItem( GDAL_DCAP_MULTIDIM_RASTER, "YES" );
2658 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "In Memory Raster" );
2659 poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2660 "Byte Int16 UInt16 Int32 UInt32 Float32 Float64 "
2661 "CInt16 CInt32 CFloat32 CFloat64" );
2662
2663 poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2664 "<CreationOptionList>"
2665 " <Option name='INTERLEAVE' type='string-select' default='BAND'>"
2666 " <Value>BAND</Value>"
2667 " <Value>PIXEL</Value>"
2668 " </Option>"
2669 "</CreationOptionList>" );
2670
2671 // Define GDAL_NO_OPEN_FOR_MEM_DRIVER macro to undefine Open() method for
2672 // MEM driver. Otherwise, bad user input can trigger easily a GDAL crash
2673 // as random pointers can be passed as a string. All code in GDAL tree
2674 // using the MEM driver use the Create() method only, so Open() is not
2675 // needed, except for esoteric uses.
2676 #ifndef GDAL_NO_OPEN_FOR_MEM_DRIVER
2677 poDriver->pfnOpen = MEMDataset::Open;
2678 poDriver->pfnIdentify = MEMDatasetIdentify;
2679 #endif
2680 poDriver->pfnCreate = MEMDataset::Create;
2681 poDriver->pfnCreateMultiDimensional = MEMDataset::CreateMultiDimensional;
2682 poDriver->pfnDelete = MEMDatasetDelete;
2683
2684 GetGDALDriverManager()->RegisterDriver( poDriver );
2685 }
2686