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