LCOV - code coverage report
Current view: top level - gcore - gdalnodatamaskband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 290 334 86.8 %
Date: 2026-08-22 15:37:05 Functions: 28 32 87.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Implementation of GDALNoDataMaskBand, a class implementing all
       5             :  *           a default band mask based on nodata values.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2007, Frank Warmerdam
      10             :  * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "gdal_priv.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <cassert>
      20             : #include <cmath>
      21             : #include <cstring>
      22             : #include <utility>
      23             : 
      24             : #include "cpl_conv.h"
      25             : #include "cpl_error.h"
      26             : #include "cpl_vsi.h"
      27             : #include "gdal.h"
      28             : #include "gdal_priv_templates.hpp"
      29             : #include "gdal_typetraits.h"
      30             : #include "vrtdataset.h"
      31             : 
      32             : //! @cond Doxygen_Suppress
      33             : /************************************************************************/
      34             : /*                         GDALNoDataMaskBand()                         */
      35             : /************************************************************************/
      36             : 
      37        1354 : GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn)
      38        1354 :     : m_poParent(poParentIn)
      39             : {
      40        1354 :     poDS = nullptr;
      41        1354 :     nBand = 0;
      42             : 
      43        1354 :     nRasterXSize = m_poParent->GetXSize();
      44        1354 :     nRasterYSize = m_poParent->GetYSize();
      45             : 
      46        1354 :     eDataType = GDT_UInt8;
      47        1354 :     m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
      48             : 
      49        1354 :     const auto eParentDT = m_poParent->GetRasterDataType();
      50        1354 :     if (eParentDT == GDT_Int64)
      51          16 :         m_nNoDataValueInt64 = m_poParent->GetNoDataValueAsInt64();
      52        1338 :     else if (eParentDT == GDT_UInt64)
      53          15 :         m_nNoDataValueUInt64 = m_poParent->GetNoDataValueAsUInt64();
      54             :     else
      55        1323 :         m_dfNoDataValue = m_poParent->GetNoDataValue();
      56        1354 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                         GDALNoDataMaskBand()                         */
      60             : /************************************************************************/
      61             : 
      62           4 : GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn,
      63           4 :                                        double dfNoDataValue)
      64           4 :     : m_poParent(poParentIn)
      65             : {
      66           4 :     poDS = nullptr;
      67           4 :     nBand = 0;
      68             : 
      69           4 :     nRasterXSize = m_poParent->GetXSize();
      70           4 :     nRasterYSize = m_poParent->GetYSize();
      71             : 
      72           4 :     eDataType = GDT_UInt8;
      73           4 :     m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
      74             : 
      75           4 :     const auto eParentDT = m_poParent->GetRasterDataType();
      76           4 :     if (eParentDT == GDT_Int64)
      77           0 :         m_nNoDataValueInt64 = static_cast<int64_t>(dfNoDataValue);
      78           4 :     else if (eParentDT == GDT_UInt64)
      79           0 :         m_nNoDataValueUInt64 = static_cast<uint64_t>(dfNoDataValue);
      80             :     else
      81           4 :         m_dfNoDataValue = dfNoDataValue;
      82           4 : }
      83             : 
      84             : /************************************************************************/
      85             : /*                        ~GDALNoDataMaskBand()                         */
      86             : /************************************************************************/
      87             : 
      88             : GDALNoDataMaskBand::~GDALNoDataMaskBand() = default;
      89             : 
      90             : /************************************************************************/
      91             : /*                          GetWorkDataType()                           */
      92             : /************************************************************************/
      93             : 
      94       18846 : static GDALDataType GetWorkDataType(GDALDataType eDataType)
      95             : {
      96       18846 :     GDALDataType eWrkDT = GDT_Unknown;
      97       18846 :     switch (eDataType)
      98             :     {
      99        1653 :         case GDT_UInt8:
     100        1653 :             eWrkDT = GDT_UInt8;
     101        1653 :             break;
     102             : 
     103        1864 :         case GDT_Int16:
     104        1864 :             eWrkDT = GDT_Int16;
     105        1864 :             break;
     106             : 
     107          67 :         case GDT_UInt16:
     108          67 :             eWrkDT = GDT_UInt16;
     109          67 :             break;
     110             : 
     111          33 :         case GDT_UInt32:
     112          33 :             eWrkDT = GDT_UInt32;
     113          33 :             break;
     114             : 
     115         134 :         case GDT_Int8:
     116             :         case GDT_Int32:
     117             :         case GDT_CInt16:
     118             :         case GDT_CInt32:
     119         134 :             eWrkDT = GDT_Int32;
     120         134 :             break;
     121             : 
     122       14874 :         case GDT_Float16:
     123             :         case GDT_CFloat16:
     124             :         case GDT_Float32:
     125             :         case GDT_CFloat32:
     126       14874 :             eWrkDT = GDT_Float32;
     127       14874 :             break;
     128             : 
     129         169 :         case GDT_Float64:
     130             :         case GDT_CFloat64:
     131         169 :             eWrkDT = GDT_Float64;
     132         169 :             break;
     133             : 
     134          52 :         case GDT_Int64:
     135             :         case GDT_UInt64:
     136          52 :             eWrkDT = eDataType;
     137          52 :             break;
     138             : 
     139           0 :         case GDT_Unknown:
     140             :         case GDT_TypeCount:
     141           0 :             CPLAssert(false);
     142             :             eWrkDT = GDT_Float64;
     143             :             break;
     144             :     }
     145       18846 :     return eWrkDT;
     146             : }
     147             : 
     148             : /************************************************************************/
     149             : /*                          IsNoDataInRange()                           */
     150             : /************************************************************************/
     151             : 
     152        1362 : bool GDALNoDataMaskBand::IsNoDataInRange(double dfNoDataValue,
     153             :                                          GDALDataType eDataTypeIn)
     154             : {
     155        1362 :     GDALDataType eWrkDT = GetWorkDataType(eDataTypeIn);
     156        1362 :     switch (eWrkDT)
     157             :     {
     158         584 :         case GDT_UInt8:
     159             :         {
     160         584 :             return GDALIsValueInRange<GByte>(dfNoDataValue);
     161             :         }
     162             : 
     163           0 :         case GDT_Int8:
     164             :         {
     165           0 :             return GDALIsValueInRange<signed char>(dfNoDataValue);
     166             :         }
     167             : 
     168         152 :         case GDT_Int16:
     169             :         {
     170         152 :             return GDALIsValueInRange<GInt16>(dfNoDataValue);
     171             :         }
     172             : 
     173          55 :         case GDT_UInt16:
     174             :         {
     175          55 :             return GDALIsValueInRange<GUInt16>(dfNoDataValue);
     176             :         }
     177             : 
     178          22 :         case GDT_UInt32:
     179             :         {
     180          22 :             return GDALIsValueInRange<GUInt32>(dfNoDataValue);
     181             :         }
     182          47 :         case GDT_Int32:
     183             :         {
     184          47 :             return GDALIsValueInRange<GInt32>(dfNoDataValue);
     185             :         }
     186             : 
     187           0 :         case GDT_UInt64:
     188             :         {
     189           0 :             return GDALIsValueInRange<uint64_t>(dfNoDataValue);
     190             :         }
     191             : 
     192           0 :         case GDT_Int64:
     193             :         {
     194           0 :             return GDALIsValueInRange<int64_t>(dfNoDataValue);
     195             :         }
     196             : 
     197           0 :         case GDT_Float16:
     198             :         {
     199           0 :             return std::isnan(dfNoDataValue) || std::isinf(dfNoDataValue) ||
     200           0 :                    GDALIsValueInRange<GFloat16>(dfNoDataValue);
     201             :         }
     202             : 
     203         401 :         case GDT_Float32:
     204             :         {
     205         745 :             return std::isnan(dfNoDataValue) || std::isinf(dfNoDataValue) ||
     206         745 :                    GDALIsValueInRange<float>(dfNoDataValue);
     207             :         }
     208             : 
     209         101 :         case GDT_Float64:
     210             :         {
     211         101 :             return true;
     212             :         }
     213             : 
     214           0 :         case GDT_CFloat16:
     215             :         case GDT_CFloat32:
     216             :         case GDT_CFloat64:
     217             :         case GDT_CInt16:
     218             :         case GDT_CInt32:
     219             :         case GDT_Unknown:
     220             :         case GDT_TypeCount:
     221           0 :             break;
     222             :     }
     223             : 
     224           0 :     CPLAssert(false);
     225             :     return false;
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                             IReadBlock()                             */
     230             : /************************************************************************/
     231             : 
     232          34 : CPLErr GDALNoDataMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff,
     233             :                                       void *pImage)
     234             : 
     235             : {
     236          34 :     const int nXOff = nXBlockOff * nBlockXSize;
     237          34 :     const int nXSizeRequest = std::min(nBlockXSize, nRasterXSize - nXOff);
     238          34 :     const int nYOff = nYBlockOff * nBlockYSize;
     239          34 :     const int nYSizeRequest = std::min(nBlockYSize, nRasterYSize - nYOff);
     240             : 
     241          34 :     if (nBlockXSize != nXSizeRequest || nBlockYSize != nYSizeRequest)
     242             :     {
     243           0 :         memset(pImage, 0, static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
     244             :     }
     245             : 
     246             :     GDALRasterIOExtraArg sExtraArg;
     247          34 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     248          68 :     return IRasterIO(GF_Read, nXOff, nYOff, nXSizeRequest, nYSizeRequest,
     249             :                      pImage, nXSizeRequest, nYSizeRequest, GDT_UInt8, 1,
     250          68 :                      nBlockXSize, &sExtraArg);
     251             : }
     252             : 
     253             : /************************************************************************/
     254             : /*                            SetZeroOr255()                            */
     255             : /************************************************************************/
     256             : 
     257             : #if (defined(__GNUC__) && !defined(__clang__))
     258             : __attribute__((optimize("tree-vectorize")))
     259             : #endif
     260         966 : static void SetZeroOr255(GByte *pabyDestAndSrc, size_t nBufSize, GByte byNoData)
     261             : {
     262     4673420 :     for (size_t i = 0; i < nBufSize; ++i)
     263             :     {
     264     4672460 :         pabyDestAndSrc[i] = (pabyDestAndSrc[i] == byNoData) ? 0 : 255;
     265             :     }
     266         966 : }
     267             : 
     268             : template <class T>
     269             : #if (defined(__GNUC__) && !defined(__clang__))
     270             : __attribute__((optimize("tree-vectorize")))
     271             : #endif
     272        3447 : static void SetZeroOr255(GByte *pabyDest, const T *panSrc, size_t nBufSize,
     273             :                          T nNoData)
     274             : {
     275      999318 :     for (size_t i = 0; i < nBufSize; ++i)
     276             :     {
     277      995871 :         pabyDest[i] = (panSrc[i] == nNoData) ? 0 : 255;
     278             :     }
     279        3447 : }
     280             : 
     281             : template <class T>
     282        1848 : static void SetZeroOr255(GByte *pabyDest, const T *panSrc, int nBufXSize,
     283             :                          int nBufYSize, GSpacing nPixelSpace,
     284             :                          GSpacing nLineSpace, T nNoData)
     285             : {
     286        1848 :     if (nPixelSpace == 1)
     287             :     {
     288        5287 :         for (int iY = 0; iY < nBufYSize; iY++)
     289             :         {
     290        3447 :             SetZeroOr255(pabyDest, panSrc, nBufXSize, nNoData);
     291        3447 :             pabyDest += nLineSpace;
     292        3447 :             panSrc += nBufXSize;
     293             :         }
     294             :     }
     295             :     else
     296             :     {
     297           8 :         size_t i = 0;
     298          40 :         for (int iY = 0; iY < nBufYSize; iY++)
     299             :         {
     300          32 :             GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     301         224 :             for (int iX = 0; iX < nBufXSize; iX++)
     302             :             {
     303         192 :                 *pabyLineDest = (panSrc[i] == nNoData) ? 0 : 255;
     304         192 :                 ++i;
     305         192 :                 pabyLineDest += nPixelSpace;
     306             :             }
     307             :         }
     308             :     }
     309        1848 : }
     310             : 
     311             : /************************************************************************/
     312             : /*                         ParentBandIsNoData()                         */
     313             : /************************************************************************/
     314             : 
     315             : /** Callback function for a VRT raster band. Transforms input band into
     316             :  * a NoData mask, which can then be resampled.
     317             :  */
     318             : template <GDALDataType GDALTransferDataType>
     319           6 : static CPLErr ParentBandIsNoData(void *poData, int nXOff, int nYOff, int nXSize,
     320             :                                  int nYSize, void *pData)
     321             : {
     322             :     using TransferType =
     323             :         typename gdal::GDALDataTypeTraits<GDALTransferDataType>::type;
     324             : 
     325           6 :     GDALRasterBand *poSrcBand = static_cast<GDALRasterBand *>(poData);
     326             : 
     327           6 :     std::unique_ptr<TransferType, decltype(&CPLFree)> pabySrc{
     328             :         static_cast<TransferType *>(
     329           6 :             VSI_MALLOC3_VERBOSE(sizeof(TransferType), nXSize, nYSize)),
     330           6 :         CPLFree};
     331           6 :     if (pabySrc == nullptr)
     332             :     {
     333           0 :         return CE_Failure;
     334             :     }
     335             : 
     336           6 :     const auto eErr = poSrcBand->RasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
     337             :                                           pabySrc.get(), nXSize, nYSize,
     338             :                                           GDALTransferDataType, 0, 0, nullptr);
     339           6 :     if (eErr != CE_None)
     340             :     {
     341           0 :         return eErr;
     342             :     }
     343             : 
     344           6 :     const size_t nPixelCount = static_cast<size_t>(nXSize) * nYSize;
     345           6 :     GByte *pabyDst = static_cast<GByte *>(pData);
     346             : 
     347           6 :     const auto maybeNoData = poSrcBand->GetNoDataValue<TransferType>();
     348           6 :     if (!maybeNoData.has_value())
     349             :     {
     350           0 :         std::fill(pabyDst, pabyDst + nPixelCount, 255);
     351           0 :         return CE_None;
     352             :     }
     353           6 :     const TransferType noData = maybeNoData.value();
     354             : 
     355          30 :     for (size_t i = 0; i < nPixelCount; i++)
     356             :     {
     357             :         if constexpr (std::is_floating_point_v<TransferType>)
     358             :         {
     359          10 :             pabyDst[i] = (std::isnan(noData) && std::isnan(pabySrc.get()[i])) ||
     360           2 :                                  ARE_REAL_EQUAL(pabySrc.get()[i], noData)
     361             :                              ? 0
     362             :                              : 255;
     363             :         }
     364             :         else
     365             :         {
     366          16 :             pabyDst[i] = pabySrc.get()[i] == noData ? 0 : 255;
     367             :         }
     368             :     }
     369             : 
     370           6 :     return CE_None;
     371             : }
     372             : 
     373             : /************************************************************************/
     374             : /*                             IRasterIO()                              */
     375             : /************************************************************************/
     376             : 
     377       17484 : CPLErr GDALNoDataMaskBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     378             :                                      int nXSize, int nYSize, void *pData,
     379             :                                      int nBufXSize, int nBufYSize,
     380             :                                      GDALDataType eBufType,
     381             :                                      GSpacing nPixelSpace, GSpacing nLineSpace,
     382             :                                      GDALRasterIOExtraArg *psExtraArg)
     383             : {
     384       17484 :     if (eRWFlag != GF_Read)
     385             :     {
     386           0 :         return CE_Failure;
     387             :     }
     388             : 
     389       17484 :     const auto eParentDT = m_poParent->GetRasterDataType();
     390       17484 :     const GDALDataType eWrkDT = GetWorkDataType(eParentDT);
     391             : 
     392       17484 :     if (psExtraArg->eResampleAlg == GRIORA_Mode)
     393             :     {
     394             :         // For mode resampling, we have to read the parent band at full resolution
     395             :         // and classify each pixel as valid / NoData.
     396             :         auto poVRT = VRTDataset::CreateVRTDataset("", nXSize, nYSize, 0,
     397          12 :                                                   GDT_UInt8, nullptr);
     398           6 :         poVRT->AddBand(GDT_Byte, nullptr);
     399             :         VRTSourcedRasterBand *poVRTBand =
     400           6 :             cpl::down_cast<VRTSourcedRasterBand *>(poVRT->GetRasterBand(1));
     401             : 
     402           6 :         switch (eWrkDT)
     403             :         {
     404           1 :             case GDT_UInt8:
     405           1 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_UInt8>,
     406           1 :                                          m_poParent);
     407           1 :                 break;
     408           1 :             case GDT_Int16:
     409           1 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Int16>,
     410           1 :                                          m_poParent);
     411           1 :                 break;
     412           0 :             case GDT_UInt16:
     413           0 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_UInt16>,
     414           0 :                                          m_poParent);
     415           0 :                 break;
     416           0 :             case GDT_Int32:
     417           0 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Int32>,
     418           0 :                                          m_poParent);
     419           0 :                 break;
     420           0 :             case GDT_UInt32:
     421           0 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_UInt32>,
     422           0 :                                          m_poParent);
     423           0 :                 break;
     424           1 :             case GDT_Float32:
     425           1 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Float32>,
     426           1 :                                          m_poParent);
     427           1 :                 break;
     428           1 :             case GDT_Float64:
     429           1 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Float64>,
     430           1 :                                          m_poParent);
     431           1 :                 break;
     432           1 :             case GDT_Int64:
     433           1 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Int64>,
     434           1 :                                          m_poParent);
     435           1 :                 break;
     436           1 :             case GDT_UInt64:
     437           1 :                 poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_UInt64>,
     438           1 :                                          m_poParent);
     439           1 :                 break;
     440           0 :             default:
     441           0 :                 CPLAssert(false);
     442             :         }
     443             : 
     444           6 :         return poVRTBand->RasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     445             :                                    nBufXSize, nBufYSize, eBufType, nPixelSpace,
     446           6 :                                    nLineSpace, psExtraArg);
     447             :     }
     448             : 
     449             :     // Optimization in common use case (#4488).
     450             :     // This avoids triggering the block cache on this band, which helps
     451             :     // reducing the global block cache consumption.
     452       17478 :     if (eBufType == GDT_UInt8 && eWrkDT == GDT_UInt8 && nPixelSpace == 1 &&
     453         963 :         nLineSpace >= nBufXSize)
     454             :     {
     455         963 :         const CPLErr eErr = m_poParent->RasterIO(
     456             :             GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     457             :             eBufType, nPixelSpace, nLineSpace, psExtraArg);
     458         963 :         if (eErr != CE_None)
     459           0 :             return eErr;
     460             : 
     461         963 :         GByte *pabyData = static_cast<GByte *>(pData);
     462         963 :         const GByte byNoData = static_cast<GByte>(m_dfNoDataValue);
     463             : 
     464         963 :         if (nLineSpace == nBufXSize)
     465             :         {
     466         962 :             const size_t nBufSize = static_cast<size_t>(nBufXSize) * nBufYSize;
     467         962 :             SetZeroOr255(pabyData, nBufSize, byNoData);
     468             :         }
     469             :         else
     470             :         {
     471           1 :             assert(nLineSpace > nBufXSize);
     472           5 :             for (int iY = 0; iY < nBufYSize; iY++)
     473             :             {
     474           4 :                 SetZeroOr255(pabyData, nBufXSize, byNoData);
     475           4 :                 pabyData += nLineSpace;
     476             :             }
     477             :         }
     478         963 :         return CE_None;
     479             :     }
     480             : 
     481             :     const auto AllocTempBufferOrFallback =
     482       16515 :         [this, eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     483             :          nBufYSize, eBufType, nPixelSpace, nLineSpace,
     484       33086 :          psExtraArg](int nWrkDTSize) -> std::pair<CPLErr, void *>
     485             :     {
     486       16515 :         auto poParentDS = m_poParent->GetDataset();
     487             :         // Check if we must simulate a memory allocation failure
     488             :         // Before checking the env variable, which is slightly expensive,
     489             :         // check first for a special dataset name, which is a cheap test.
     490             :         const char *pszOptVal =
     491       16515 :             poParentDS && strcmp(poParentDS->GetDescription(), "__debug__") == 0
     492       33030 :                 ? CPLGetConfigOption(
     493             :                       "GDAL_SIMUL_MEM_ALLOC_FAILURE_NODATA_MASK_BAND", "NO")
     494       16515 :                 : "NO";
     495             :         const bool bSimulMemAllocFailure =
     496       33026 :             EQUAL(pszOptVal, "ALWAYS") ||
     497       16511 :             (CPLTestBool(pszOptVal) &&
     498          14 :              GDALMajorObject::GetMetadataItem(__func__, "__INTERNAL__") ==
     499       16515 :                  nullptr);
     500       16515 :         void *pTemp = nullptr;
     501       16515 :         if (!bSimulMemAllocFailure)
     502             :         {
     503       16503 :             CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
     504       16503 :             pTemp = VSI_MALLOC3_VERBOSE(nWrkDTSize, nBufXSize, nBufYSize);
     505             :         }
     506       16515 :         if (!pTemp)
     507             :         {
     508             :             const bool bAllocHasAlreadyFailed =
     509          12 :                 GDALMajorObject::GetMetadataItem(__func__, "__INTERNAL__") !=
     510          12 :                 nullptr;
     511          12 :             CPLError(bAllocHasAlreadyFailed ? CE_Failure : CE_Warning,
     512             :                      CPLE_OutOfMemory,
     513             :                      "GDALNoDataMaskBand::IRasterIO(): cannot allocate %d x %d "
     514             :                      "x %d bytes%s",
     515             :                      nBufXSize, nBufYSize, nWrkDTSize,
     516             :                      bAllocHasAlreadyFailed
     517             :                          ? ""
     518             :                          : ". Falling back to block-based approach");
     519          12 :             if (bAllocHasAlreadyFailed)
     520           2 :                 return std::pair(CE_Failure, nullptr);
     521             :             // Sets a metadata item to prevent potential infinite recursion
     522          10 :             GDALMajorObject::SetMetadataItem(__func__, "IN", "__INTERNAL__");
     523          10 :             const CPLErr eErr = GDALRasterBand::IRasterIO(
     524             :                 eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     525          10 :                 nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     526          10 :             GDALMajorObject::SetMetadataItem(__func__, nullptr, "__INTERNAL__");
     527          10 :             return std::pair(eErr, nullptr);
     528             :         }
     529       16503 :         return std::pair(CE_None, pTemp);
     530       16515 :     };
     531             : 
     532       16515 :     if (eBufType == GDT_UInt8)
     533             :     {
     534       16386 :         const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
     535       16386 :         auto [eErr, pTemp] = AllocTempBufferOrFallback(nWrkDTSize);
     536       16386 :         if (!pTemp)
     537          12 :             return eErr;
     538             : 
     539       32748 :         eErr = m_poParent->RasterIO(
     540             :             GF_Read, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize, nBufYSize,
     541       16374 :             eWrkDT, nWrkDTSize, static_cast<GSpacing>(nBufXSize) * nWrkDTSize,
     542             :             psExtraArg);
     543       16374 :         if (eErr != CE_None)
     544             :         {
     545           0 :             VSIFree(pTemp);
     546           0 :             return eErr;
     547             :         }
     548             : 
     549       16374 :         const bool bIsNoDataNan = std::isnan(m_dfNoDataValue) != 0;
     550       16374 :         GByte *pabyDest = static_cast<GByte *>(pData);
     551             : 
     552             :         /* --------------------------------------------------------------------
     553             :          */
     554             :         /*      Process different cases. */
     555             :         /* --------------------------------------------------------------------
     556             :          */
     557       16374 :         switch (eWrkDT)
     558             :         {
     559           1 :             case GDT_UInt8:
     560             :             {
     561           1 :                 const auto nNoData = static_cast<GByte>(m_dfNoDataValue);
     562           1 :                 const auto *panSrc = static_cast<const GByte *>(pTemp);
     563           1 :                 SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
     564             :                              nPixelSpace, nLineSpace, nNoData);
     565             :             }
     566           1 :             break;
     567             : 
     568        1708 :             case GDT_Int16:
     569             :             {
     570        1708 :                 const auto nNoData = static_cast<int16_t>(m_dfNoDataValue);
     571        1708 :                 const auto *panSrc = static_cast<const int16_t *>(pTemp);
     572        1708 :                 SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
     573             :                              nPixelSpace, nLineSpace, nNoData);
     574             :             }
     575        1708 :             break;
     576             : 
     577          10 :             case GDT_UInt16:
     578             :             {
     579          10 :                 const auto nNoData = static_cast<uint16_t>(m_dfNoDataValue);
     580          10 :                 const auto *panSrc = static_cast<const uint16_t *>(pTemp);
     581          10 :                 SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
     582             :                              nPixelSpace, nLineSpace, nNoData);
     583             :             }
     584          10 :             break;
     585             : 
     586           9 :             case GDT_UInt32:
     587             :             {
     588           9 :                 const auto nNoData = static_cast<GUInt32>(m_dfNoDataValue);
     589           9 :                 const auto *panSrc = static_cast<const GUInt32 *>(pTemp);
     590           9 :                 SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
     591             :                              nPixelSpace, nLineSpace, nNoData);
     592             :             }
     593           9 :             break;
     594             : 
     595          84 :             case GDT_Int32:
     596             :             {
     597          84 :                 const auto nNoData = static_cast<GInt32>(m_dfNoDataValue);
     598          84 :                 const auto *panSrc = static_cast<const GInt32 *>(pTemp);
     599          84 :                 SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
     600             :                              nPixelSpace, nLineSpace, nNoData);
     601             :             }
     602          84 :             break;
     603             : 
     604       14465 :             case GDT_Float32:
     605             :             {
     606       14465 :                 const float fNoData = static_cast<float>(m_dfNoDataValue);
     607       14465 :                 const float *pafSrc = static_cast<const float *>(pTemp);
     608             : 
     609       14465 :                 size_t i = 0;
     610       32795 :                 for (int iY = 0; iY < nBufYSize; iY++)
     611             :                 {
     612       18330 :                     GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     613    15514100 :                     for (int iX = 0; iX < nBufXSize; iX++)
     614             :                     {
     615    15495700 :                         const float fVal = pafSrc[i];
     616    15495700 :                         if (bIsNoDataNan && std::isnan(fVal))
     617          69 :                             *pabyLineDest = 0;
     618    15495700 :                         else if (ARE_REAL_EQUAL(fVal, fNoData))
     619     1009610 :                             *pabyLineDest = 0;
     620             :                         else
     621    14486100 :                             *pabyLineDest = 255;
     622    15495700 :                         ++i;
     623    15495700 :                         pabyLineDest += nPixelSpace;
     624             :                     }
     625             :                 }
     626             :             }
     627       14465 :             break;
     628             : 
     629          61 :             case GDT_Float64:
     630             :             {
     631          61 :                 const double *padfSrc = static_cast<const double *>(pTemp);
     632             : 
     633          61 :                 size_t i = 0;
     634         518 :                 for (int iY = 0; iY < nBufYSize; iY++)
     635             :                 {
     636         457 :                     GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     637        6379 :                     for (int iX = 0; iX < nBufXSize; iX++)
     638             :                     {
     639        5922 :                         const double dfVal = padfSrc[i];
     640        5922 :                         if (bIsNoDataNan && std::isnan(dfVal))
     641          75 :                             *pabyLineDest = 0;
     642        5847 :                         else if (ARE_REAL_EQUAL(dfVal, m_dfNoDataValue))
     643         241 :                             *pabyLineDest = 0;
     644             :                         else
     645        5606 :                             *pabyLineDest = 255;
     646        5922 :                         ++i;
     647        5922 :                         pabyLineDest += nPixelSpace;
     648             :                     }
     649             :                 }
     650             :             }
     651          61 :             break;
     652             : 
     653          18 :             case GDT_Int64:
     654             :             {
     655          18 :                 const auto *panSrc = static_cast<const int64_t *>(pTemp);
     656          18 :                 SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
     657             :                              nPixelSpace, nLineSpace, m_nNoDataValueInt64);
     658             :             }
     659          18 :             break;
     660             : 
     661          18 :             case GDT_UInt64:
     662             :             {
     663          18 :                 const auto *panSrc = static_cast<const uint64_t *>(pTemp);
     664          18 :                 SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
     665             :                              nPixelSpace, nLineSpace, m_nNoDataValueUInt64);
     666             :             }
     667          18 :             break;
     668             : 
     669           0 :             default:
     670           0 :                 CPLAssert(false);
     671             :                 break;
     672             :         }
     673             : 
     674       16374 :         VSIFree(pTemp);
     675       16374 :         return CE_None;
     676             :     }
     677             : 
     678             :     // Output buffer is non-Byte. Ask for Byte and expand to user requested
     679             :     // type
     680         129 :     auto [eErr, pTemp] = AllocTempBufferOrFallback(sizeof(GByte));
     681         129 :     if (!pTemp)
     682           0 :         return eErr;
     683             : 
     684         129 :     eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize,
     685             :                      nBufYSize, GDT_UInt8, 1, nBufXSize, psExtraArg);
     686         129 :     if (eErr != CE_None)
     687             :     {
     688           0 :         VSIFree(pTemp);
     689           0 :         return eErr;
     690             :     }
     691             : 
     692         290 :     for (int iY = 0; iY < nBufYSize; iY++)
     693             :     {
     694         161 :         GDALCopyWords64(
     695         161 :             static_cast<GByte *>(pTemp) + static_cast<size_t>(iY) * nBufXSize,
     696         161 :             GDT_UInt8, 1, static_cast<GByte *>(pData) + iY * nLineSpace,
     697             :             eBufType, static_cast<int>(nPixelSpace), nBufXSize);
     698             :     }
     699         129 :     VSIFree(pTemp);
     700         129 :     return CE_None;
     701             : }
     702             : 
     703             : /************************************************************************/
     704             : /*                EmitErrorMessageIfWriteNotSupported()                 */
     705             : /************************************************************************/
     706             : 
     707           2 : bool GDALNoDataMaskBand::EmitErrorMessageIfWriteNotSupported(
     708             :     const char *pszCaller) const
     709             : {
     710           2 :     ReportError(CE_Failure, CPLE_NoWriteAccess,
     711             :                 "%s: attempt to write to a nodata implicit mask band.",
     712             :                 pszCaller);
     713             : 
     714           2 :     return true;
     715             : }
     716             : 
     717             : //! @endcond

Generated by: LCOV version 1.14