1 /******************************************************************************
2  *
3  * Project:  GDAL Core
4  * Purpose:  Implementation of a dataset overview warping class
5  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
6  *
7  ******************************************************************************
8  * Copyright (c) 2014, Even Rouault, <even dot rouault at spatialys dot com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "cpl_port.h"
30 #include "gdal_priv.h"
31 
32 #include <cstring>
33 
34 #include "cpl_conv.h"
35 #include "cpl_error.h"
36 #include "cpl_progress.h"
37 #include "cpl_string.h"
38 #include "gdal.h"
39 #include "gdal_mdreader.h"
40 #include "gdal_proxy.h"
41 
42 CPL_CVSID("$Id: gdaloverviewdataset.cpp 126b0897e64c233ed06ca072549e110bb6b28ced 2021-04-20 16:42:23 +0200 Even Rouault $")
43 
44 /** In GDAL, GDALRasterBand::GetOverview() returns a stand-alone band, that may
45     have no parent dataset. This can be inconvenient in certain contexts, where
46     cross-band processing must be done, or when API expect a fully fledged
47     dataset.  Furthermore even if overview band has a container dataset, that
48     one often fails to declare its projection, geotransform, etc... which make
49     it somehow useless. GDALOverviewDataset remedies to those deficiencies.
50 */
51 
52 class GDALOverviewBand;
53 
54 /* ******************************************************************** */
55 /*                          GDALOverviewDataset                         */
56 /* ******************************************************************** */
57 
58 class GDALOverviewDataset final: public GDALDataset
59 {
60   private:
61     friend class GDALOverviewBand;
62 
63     GDALDataset* poMainDS = nullptr;
64 
65     GDALDataset* poOvrDS = nullptr;  // Will be often NULL.
66     int          nOvrLevel = 0;
67     int          bThisLevelOnly = 0;
68 
69     int          nGCPCount = 0;
70     GDAL_GCP    *pasGCPList = nullptr;
71     char       **papszMD_RPC = nullptr;
72     char       **papszMD_GEOLOCATION = nullptr;
73     GDALOverviewBand* m_poMaskBand = nullptr;
74 
75     static void  Rescale( char**& papszMD, const char* pszItem,
76                           double dfRatio, double dfDefaultVal );
77 
78   protected:
79     CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
80                       void *, int, int, GDALDataType,
81                       int, int *,
82                       GSpacing, GSpacing, GSpacing,
83                       GDALRasterIOExtraArg* psExtraArg ) override;
84 
85   public:
86     GDALOverviewDataset( GDALDataset* poMainDS,
87                          int nOvrLevel,
88                          int bThisLevelOnly );
89     ~GDALOverviewDataset() override;
90 
91     const OGRSpatialReference* GetSpatialRef() const override;
92     CPLErr GetGeoTransform( double * ) override;
93 
94     int GetGCPCount() override;
95     const OGRSpatialReference *GetGCPSpatialRef() const override;
96     const GDAL_GCP *GetGCPs() override;
97 
98     char  **GetMetadata( const char * pszDomain = "" ) override;
99     const char *GetMetadataItem( const char * pszName,
100                                  const char * pszDomain = "" ) override;
101 
102     int CloseDependentDatasets() override;
103 
104   private:
105     CPL_DISALLOW_COPY_ASSIGN(GDALOverviewDataset)
106 };
107 
108 /* ******************************************************************** */
109 /*                           GDALOverviewBand                           */
110 /* ******************************************************************** */
111 
112 class GDALOverviewBand final: public GDALProxyRasterBand
113 {
114   protected:
115     friend class GDALOverviewDataset;
116 
117     GDALRasterBand*         poUnderlyingBand = nullptr;
118     GDALRasterBand* RefUnderlyingRasterBand() override;
119 
120     CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
121                       void *, int, int, GDALDataType,
122                       GSpacing, GSpacing,
123                       GDALRasterIOExtraArg* psExtraArg ) override;
124 
125   public:
126     GDALOverviewBand( GDALOverviewDataset* poDS, int nBand );
127     ~GDALOverviewBand() override;
128 
129     CPLErr FlushCache() override;
130 
131     int GetOverviewCount() override;
132     GDALRasterBand *GetOverview( int ) override;
133 
134     int GetMaskFlags() override;
135     GDALRasterBand* GetMaskBand() override;
136 
137   private:
138     CPL_DISALLOW_COPY_ASSIGN(GDALOverviewBand)
139 };
140 
141 /************************************************************************/
142 /*                           GetOverviewEx()                            */
143 /************************************************************************/
144 
GetOverviewEx(GDALRasterBand * poBand,int nLevel)145 static GDALRasterBand* GetOverviewEx(GDALRasterBand* poBand, int nLevel)
146 {
147     if( nLevel == -1 )
148         return poBand;
149     return poBand->GetOverview(nLevel);
150 }
151 
152 /************************************************************************/
153 /*                       GDALCreateOverviewDataset()                    */
154 /************************************************************************/
155 
156 // Takes a reference on poMainDS in case of success.
157 // nOvrLevel=-1 means the full resolution dataset (only useful if
158 // bThisLevelOnly = false to expose a dataset without its overviews)
GDALCreateOverviewDataset(GDALDataset * poMainDS,int nOvrLevel,int bThisLevelOnly)159 GDALDataset* GDALCreateOverviewDataset( GDALDataset* poMainDS, int nOvrLevel,
160                                         int bThisLevelOnly )
161 {
162     // Sanity checks.
163     const int nBands = poMainDS->GetRasterCount();
164     if( nBands == 0 )
165         return nullptr;
166 
167     auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
168     for( int i = 1; i<= nBands; ++i )
169     {
170         auto poBand = GetOverviewEx(poMainDS->GetRasterBand(i), nOvrLevel);
171         if( poBand == nullptr )
172         {
173             return nullptr;
174         }
175         if( poBand->GetXSize() != poFirstBand->GetXSize() ||
176             poBand->GetYSize() != poFirstBand->GetYSize() )
177         {
178             return nullptr;
179         }
180     }
181 
182     return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly);
183 }
184 
185 /************************************************************************/
186 /*                        GDALOverviewDataset()                         */
187 /************************************************************************/
188 
GDALOverviewDataset(GDALDataset * poMainDSIn,int nOvrLevelIn,int bThisLevelOnlyIn)189 GDALOverviewDataset::GDALOverviewDataset( GDALDataset* poMainDSIn,
190                                           int nOvrLevelIn,
191                                           int bThisLevelOnlyIn ) :
192     poMainDS(poMainDSIn),
193     nOvrLevel(nOvrLevelIn),
194     bThisLevelOnly(bThisLevelOnlyIn)
195 {
196     poMainDSIn->Reference();
197     eAccess = poMainDS->GetAccess();
198     auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
199     nRasterXSize = poFirstBand->GetXSize();
200     nRasterYSize = poFirstBand->GetYSize();
201     poOvrDS = poFirstBand->GetDataset();
202     if( nOvrLevel != -1 && poOvrDS != nullptr && poOvrDS == poMainDS )
203     {
204         CPLDebug( "GDAL",
205                   "Dataset of overview is the same as the main band. "
206                   "This is not expected");
207         poOvrDS = nullptr;
208     }
209     nBands = poMainDS->GetRasterCount();
210     for( int i = 0; i < nBands; ++i )
211     {
212         SetBand(i+1, new GDALOverviewBand(this, i+1));
213     }
214 
215     if( poFirstBand->GetMaskFlags() == GMF_PER_DATASET )
216     {
217         auto poOvrMaskBand = poFirstBand->GetMaskBand();
218         if( poOvrMaskBand  && poOvrMaskBand->GetXSize() == nRasterXSize &&
219             poOvrMaskBand->GetYSize() == nRasterYSize )
220         {
221             m_poMaskBand = new GDALOverviewBand(this, 0);
222         }
223     }
224 
225     // We create a fake driver that has the same name as the original
226     // one, but we cannot use the real driver object, so that code
227     // doesn't try to cast the GDALOverviewDataset* as a native dataset
228     // object.
229     if( poMainDS->GetDriver() != nullptr )
230     {
231         poDriver = new GDALDriver();
232         poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
233         poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
234     }
235 
236     if( poOvrDS )
237         poOvrDS->SetEnableOverviews(false);
238 
239     SetDescription( poMainDS->GetDescription() );
240 
241     CPLDebug( "GDAL", "GDALOverviewDataset(%s, this=%p) creation.",
242               poMainDS->GetDescription(), this );
243 
244     papszOpenOptions = CSLDuplicate(poMainDS->GetOpenOptions());
245     // Add OVERVIEW_LEVEL if not called from GDALOpenEx(), but directly.
246     papszOpenOptions = CSLSetNameValue(papszOpenOptions, "OVERVIEW_LEVEL",
247         nOvrLevel == -1 ? "NONE" :
248         CPLSPrintf("%d%s", nOvrLevel, bThisLevelOnly ? " only" :""));
249 }
250 
251 /************************************************************************/
252 /*                       ~GDALOverviewDataset()                         */
253 /************************************************************************/
254 
~GDALOverviewDataset()255 GDALOverviewDataset::~GDALOverviewDataset()
256 {
257     GDALOverviewDataset::FlushCache();
258 
259     GDALOverviewDataset::CloseDependentDatasets();
260 
261     if( nGCPCount > 0 )
262     {
263         GDALDeinitGCPs( nGCPCount, pasGCPList );
264         CPLFree( pasGCPList );
265     }
266     CSLDestroy(papszMD_RPC);
267 
268     CSLDestroy(papszMD_GEOLOCATION);
269 
270     delete poDriver;
271 }
272 
273 /************************************************************************/
274 /*                      CloseDependentDatasets()                        */
275 /************************************************************************/
276 
CloseDependentDatasets()277 int GDALOverviewDataset::CloseDependentDatasets()
278 {
279     bool bRet = false;
280 
281     if( poMainDS )
282     {
283         for( int i = 0; i < nBands; ++i )
284         {
285             GDALOverviewBand* const band =
286                 cpl::down_cast<GDALOverviewBand*>(papoBands[i]);
287             band->poUnderlyingBand = nullptr;
288         }
289         if( poMainDS->ReleaseRef() )
290             bRet = true;
291         poMainDS = nullptr;
292     }
293 
294     if( m_poMaskBand )
295     {
296         m_poMaskBand->poUnderlyingBand = nullptr;
297         delete m_poMaskBand;
298         m_poMaskBand = nullptr;
299     }
300 
301     return bRet;
302 }
303 
304 /************************************************************************/
305 /*                             IRasterIO()                              */
306 /*                                                                      */
307 /*      The default implementation of IRasterIO() is to pass the        */
308 /*      request off to each band objects rasterio methods with          */
309 /*      appropriate arguments.                                          */
310 /************************************************************************/
311 
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GSpacing nPixelSpace,GSpacing nLineSpace,GSpacing nBandSpace,GDALRasterIOExtraArg * psExtraArg)312 CPLErr GDALOverviewDataset::IRasterIO( GDALRWFlag eRWFlag,
313                                        int nXOff, int nYOff,
314                                        int nXSize, int nYSize,
315                                        void * pData,
316                                        int nBufXSize, int nBufYSize,
317                                        GDALDataType eBufType,
318                                        int nBandCount, int *panBandMap,
319                                        GSpacing nPixelSpace,
320                                        GSpacing nLineSpace,
321                                        GSpacing nBandSpace,
322                                        GDALRasterIOExtraArg* psExtraArg )
323 
324 {
325     // Try to pass the request to the most appropriate overview dataset.
326     if( nBufXSize < nXSize && nBufYSize < nYSize )
327     {
328         int bTried = FALSE;
329         const CPLErr eErr =
330             TryOverviewRasterIO( eRWFlag,
331                                  nXOff, nYOff, nXSize, nYSize,
332                                  pData, nBufXSize, nBufYSize,
333                                  eBufType,
334                                  nBandCount, panBandMap,
335                                  nPixelSpace, nLineSpace,
336                                  nBandSpace,
337                                  psExtraArg,
338                                  &bTried );
339         if( bTried )
340             return eErr;
341     }
342 
343     // In case the overview bands are really linked to a dataset, then issue
344     // the request to that dataset.
345     if( nOvrLevel != -1 && poOvrDS != nullptr )
346     {
347         return poOvrDS->RasterIO(
348             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
349             eBufType, nBandCount, panBandMap, nPixelSpace,
350             nLineSpace, nBandSpace,
351             psExtraArg);
352     }
353 
354     GDALProgressFunc  pfnProgressGlobal = psExtraArg->pfnProgress;
355     void *pProgressDataGlobal = psExtraArg->pProgressData;
356     CPLErr eErr = CE_None;
357 
358     for( int iBandIndex = 0;
359          iBandIndex < nBandCount && eErr == CE_None;
360          ++iBandIndex )
361     {
362         GDALOverviewBand *poBand =
363             cpl::down_cast<GDALOverviewBand *>(
364                 GetRasterBand(panBandMap[iBandIndex]) );
365         GByte *pabyBandData =
366             static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
367 
368         psExtraArg->pfnProgress = GDALScaledProgress;
369         psExtraArg->pProgressData =
370             GDALCreateScaledProgress( 1.0 * iBandIndex / nBandCount,
371                                       1.0 * (iBandIndex + 1) / nBandCount,
372                                       pfnProgressGlobal,
373                                       pProgressDataGlobal );
374 
375         eErr = poBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
376                                   pabyBandData,
377                                   nBufXSize, nBufYSize,
378                                   eBufType, nPixelSpace,
379                                   nLineSpace, psExtraArg );
380 
381         GDALDestroyScaledProgress( psExtraArg->pProgressData );
382     }
383 
384     psExtraArg->pfnProgress = pfnProgressGlobal;
385     psExtraArg->pProgressData = pProgressDataGlobal;
386 
387     return eErr;
388 }
389 
390 /************************************************************************/
391 /*                           GetSpatialRef()                            */
392 /************************************************************************/
393 
GetSpatialRef() const394 const OGRSpatialReference *GDALOverviewDataset::GetSpatialRef() const
395 
396 {
397     return poMainDS->GetSpatialRef();
398 }
399 
400 /************************************************************************/
401 /*                          GetGeoTransform()                           */
402 /************************************************************************/
403 
GetGeoTransform(double * padfTransform)404 CPLErr GDALOverviewDataset::GetGeoTransform( double * padfTransform )
405 
406 {
407     double adfGeoTransform[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
408     if( poMainDS->GetGeoTransform(adfGeoTransform) != CE_None )
409         return CE_Failure;
410 
411     adfGeoTransform[1] *=
412         static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
413     adfGeoTransform[2] *=
414         static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
415     adfGeoTransform[4] *=
416         static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
417     adfGeoTransform[5] *=
418         static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
419 
420     memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
421 
422     return CE_None;
423 }
424 
425 /************************************************************************/
426 /*                            GetGCPCount()                             */
427 /************************************************************************/
428 
GetGCPCount()429 int GDALOverviewDataset::GetGCPCount()
430 
431 {
432     return poMainDS->GetGCPCount();
433 }
434 
435 /************************************************************************/
436 /*                          GetGCPSpatialRef()                          */
437 /************************************************************************/
438 
GetGCPSpatialRef() const439 const OGRSpatialReference *GDALOverviewDataset::GetGCPSpatialRef() const
440 
441 {
442     return poMainDS->GetGCPSpatialRef();
443 }
444 
445 /************************************************************************/
446 /*                               GetGCPs()                              */
447 /************************************************************************/
448 
GetGCPs()449 const GDAL_GCP *GDALOverviewDataset::GetGCPs()
450 
451 {
452     if( pasGCPList != nullptr )
453         return pasGCPList;
454 
455     const GDAL_GCP* pasGCPsMain = poMainDS->GetGCPs();
456     if( pasGCPsMain == nullptr )
457         return nullptr;
458     nGCPCount = poMainDS->GetGCPCount();
459 
460     pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPsMain );
461     for( int i = 0; i < nGCPCount; ++i )
462     {
463         pasGCPList[i].dfGCPPixel *= static_cast<double>(nRasterXSize) /
464             poMainDS->GetRasterXSize();
465         pasGCPList[i].dfGCPLine *= static_cast<double>(nRasterYSize) /
466             poMainDS->GetRasterYSize();
467     }
468     return pasGCPList;
469 }
470 
471 /************************************************************************/
472 /*                             Rescale()                                */
473 /************************************************************************/
474 
Rescale(char ** & papszMD,const char * pszItem,double dfRatio,double dfDefaultVal)475 void GDALOverviewDataset::Rescale( char**& papszMD, const char* pszItem,
476                                    double dfRatio, double dfDefaultVal )
477 {
478     double dfVal =
479         CPLAtofM( CSLFetchNameValueDef(papszMD, pszItem,
480                                        CPLSPrintf("%.18g", dfDefaultVal)) );
481     dfVal *= dfRatio;
482     papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.18g", dfVal));
483 }
484 
485 /************************************************************************/
486 /*                            GetMetadata()                             */
487 /************************************************************************/
488 
GetMetadata(const char * pszDomain)489 char  **GDALOverviewDataset::GetMetadata( const char * pszDomain )
490 {
491     if( poOvrDS != nullptr )
492     {
493         char** papszMD = poOvrDS->GetMetadata(pszDomain);
494         if( papszMD != nullptr )
495             return papszMD;
496     }
497 
498     char** papszMD = poMainDS->GetMetadata(pszDomain);
499 
500     // We may need to rescale some values from the RPC metadata domain.
501     if( pszDomain != nullptr && EQUAL(pszDomain, MD_DOMAIN_RPC) &&
502         papszMD != nullptr )
503     {
504         if( papszMD_RPC )
505             return papszMD_RPC;
506         papszMD_RPC = CSLDuplicate(papszMD);
507 
508         Rescale( papszMD_RPC, RPC_LINE_OFF,
509                  static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
510                  0.0 );
511         Rescale( papszMD_RPC, RPC_LINE_SCALE,
512                  static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
513                  1.0 );
514         Rescale( papszMD_RPC, RPC_SAMP_OFF,
515                  static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
516                  0.0 );
517         Rescale( papszMD_RPC, RPC_SAMP_SCALE,
518                  static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
519                  1.0 );
520 
521         papszMD = papszMD_RPC;
522     }
523 
524     // We may need to rescale some values from the GEOLOCATION metadata domain.
525     if( pszDomain != nullptr && EQUAL(pszDomain, "GEOLOCATION") &&
526         papszMD != nullptr )
527     {
528         if( papszMD_GEOLOCATION )
529             return papszMD_GEOLOCATION;
530         papszMD_GEOLOCATION = CSLDuplicate(papszMD);
531 
532         Rescale( papszMD_GEOLOCATION, "PIXEL_OFFSET",
533                  static_cast<double>(poMainDS->GetRasterXSize()) /
534                  nRasterXSize, 0.0 );
535         Rescale( papszMD_GEOLOCATION, "LINE_OFFSET",
536                  static_cast<double>(poMainDS->GetRasterYSize()) /
537                  nRasterYSize, 0.0 );
538 
539         Rescale( papszMD_GEOLOCATION, "PIXEL_STEP",
540                  static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
541                  1.0 );
542         Rescale( papszMD_GEOLOCATION, "LINE_STEP",
543                  static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
544                  1.0 );
545 
546         papszMD = papszMD_GEOLOCATION;
547     }
548 
549     return papszMD;
550 }
551 
552 /************************************************************************/
553 /*                          GetMetadataItem()                           */
554 /************************************************************************/
555 
GetMetadataItem(const char * pszName,const char * pszDomain)556 const char *GDALOverviewDataset::GetMetadataItem( const char * pszName,
557                                                   const char * pszDomain )
558 {
559     if( poOvrDS != nullptr )
560     {
561         const char* pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
562         if( pszValue != nullptr )
563             return pszValue;
564     }
565 
566     if( pszDomain != nullptr && (EQUAL(pszDomain, "RPC") ||
567                               EQUAL(pszDomain, "GEOLOCATION")) )
568     {
569         char** papszMD = GetMetadata(pszDomain);
570         return CSLFetchNameValue(papszMD, pszName);
571     }
572 
573     return poMainDS->GetMetadataItem(pszName, pszDomain);
574 }
575 
576 /************************************************************************/
577 /*                          GDALOverviewBand()                          */
578 /************************************************************************/
579 
GDALOverviewBand(GDALOverviewDataset * poDSIn,int nBandIn)580 GDALOverviewBand::GDALOverviewBand( GDALOverviewDataset* poDSIn, int nBandIn )
581 {
582     poDS = poDSIn;
583     nBand = nBandIn;
584     nRasterXSize = poDSIn->nRasterXSize;
585     nRasterYSize = poDSIn->nRasterYSize;
586     if( nBandIn == 0 )
587     {
588         poUnderlyingBand =
589             GetOverviewEx(poDSIn->poMainDS->GetRasterBand(1), poDSIn->nOvrLevel)->GetMaskBand();
590     }
591     else
592     {
593         poUnderlyingBand =
594             GetOverviewEx(poDSIn->poMainDS->GetRasterBand(nBandIn), poDSIn->nOvrLevel);
595     }
596     eDataType = poUnderlyingBand->GetRasterDataType();
597     poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
598 }
599 
600 /************************************************************************/
601 /*                         ~GDALOverviewBand()                          */
602 /************************************************************************/
603 
~GDALOverviewBand()604 GDALOverviewBand::~GDALOverviewBand()
605 {
606     GDALOverviewBand::FlushCache();
607 }
608 
609 /************************************************************************/
610 /*                              FlushCache()                            */
611 /************************************************************************/
612 
FlushCache()613 CPLErr GDALOverviewBand::FlushCache()
614 {
615     if( poUnderlyingBand )
616         return poUnderlyingBand->FlushCache();
617     return CE_None;
618 }
619 
620 /************************************************************************/
621 /*                        RefUnderlyingRasterBand()                     */
622 /************************************************************************/
623 
RefUnderlyingRasterBand()624 GDALRasterBand* GDALOverviewBand::RefUnderlyingRasterBand()
625 {
626     if( poUnderlyingBand )
627         return poUnderlyingBand;
628 
629     return nullptr;
630 }
631 
632 /************************************************************************/
633 /*                         GetOverviewCount()                           */
634 /************************************************************************/
635 
GetOverviewCount()636 int GDALOverviewBand::GetOverviewCount()
637 {
638     GDALOverviewDataset * const poOvrDS =
639         cpl::down_cast<GDALOverviewDataset *>(poDS);
640     if( poOvrDS->bThisLevelOnly )
641         return 0;
642     GDALDataset * const poMainDS = poOvrDS->poMainDS;
643     GDALRasterBand* poMainBand =
644         ( nBand == 0 ) ? poMainDS->GetRasterBand(1)->GetMaskBand() :
645                          poMainDS->GetRasterBand(nBand);
646     auto poUnderlyingDS = poUnderlyingBand ? poUnderlyingBand->GetDataset() : nullptr;
647     if( poUnderlyingDS )
648         poUnderlyingDS->SetEnableOverviews(true);
649     const int nRet = poMainBand->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
650     if( poUnderlyingDS )
651         poUnderlyingDS->SetEnableOverviews(false);
652     return nRet;
653 }
654 
655 /************************************************************************/
656 /*                           GetOverview()                              */
657 /************************************************************************/
658 
GetOverview(int iOvr)659 GDALRasterBand *GDALOverviewBand::GetOverview( int iOvr )
660 {
661     if( iOvr < 0 || iOvr >= GetOverviewCount() )
662         return nullptr;
663     GDALOverviewDataset * const poOvrDS =
664         cpl::down_cast<GDALOverviewDataset *>(poDS);
665     GDALDataset * const poMainDS = poOvrDS->poMainDS;
666     GDALRasterBand* poMainBand =
667         ( nBand == 0 ) ? poMainDS->GetRasterBand(1)->GetMaskBand() :
668                          poMainDS->GetRasterBand(nBand);
669     auto poUnderlyingDS = poUnderlyingBand ? poUnderlyingBand->GetDataset() : nullptr;
670     if( poUnderlyingDS )
671         poUnderlyingDS->SetEnableOverviews(true);
672     auto poRet = poMainBand->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
673     if( poUnderlyingDS )
674         poUnderlyingDS->SetEnableOverviews(false);
675     return poRet;
676 }
677 
678 /************************************************************************/
679 /*                           GetMaskFlags()                             */
680 /************************************************************************/
681 
GetMaskFlags()682 int GDALOverviewBand::GetMaskFlags()
683 {
684     GDALOverviewDataset * const poOvrDS = cpl::down_cast<GDALOverviewDataset *>(poDS);
685     if( nBand != 0 && poOvrDS->m_poMaskBand )
686         return GMF_PER_DATASET;
687     return GDALProxyRasterBand::GetMaskFlags();
688 }
689 
690 /************************************************************************/
691 /*                           GetMaskBand()                              */
692 /************************************************************************/
693 
GetMaskBand()694 GDALRasterBand* GDALOverviewBand::GetMaskBand()
695 {
696     GDALOverviewDataset * const poOvrDS = cpl::down_cast<GDALOverviewDataset *>(poDS);
697     if( nBand != 0 && poOvrDS->m_poMaskBand )
698         return poOvrDS->m_poMaskBand;
699     return GDALProxyRasterBand::GetMaskBand();
700 }
701 
702 /************************************************************************/
703 /*                            IRasterIO()                               */
704 /************************************************************************/
705 
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpace,GSpacing nLineSpace,GDALRasterIOExtraArg * psExtraArg)706 CPLErr GDALOverviewBand::IRasterIO( GDALRWFlag eRWFlag,
707                                    int nXOff, int nYOff, int nXSize, int nYSize,
708                                    void * pData, int nBufXSize, int nBufYSize,
709                                    GDALDataType eBufType,
710                                    GSpacing nPixelSpace, GSpacing nLineSpace,
711                                    GDALRasterIOExtraArg* psExtraArg )
712 {
713     // Try to pass the request to the most appropriate overview.
714     if( nBufXSize < nXSize && nBufYSize < nYSize )
715     {
716         int bTried = FALSE;
717         const CPLErr eErr =
718             TryOverviewRasterIO( eRWFlag,
719                                  nXOff, nYOff, nXSize, nYSize,
720                                  pData, nBufXSize, nBufYSize,
721                                  eBufType,
722                                  nPixelSpace, nLineSpace,
723                                  psExtraArg,
724                                  &bTried );
725         if( bTried )
726             return eErr;
727     }
728 
729     return GDALProxyRasterBand::IRasterIO(eRWFlag,
730                                  nXOff, nYOff, nXSize, nYSize,
731                                  pData, nBufXSize, nBufYSize,
732                                  eBufType,
733                                  nPixelSpace, nLineSpace,
734                                  psExtraArg);
735 }
736