Coverage Report

Created: 2025-06-13 06:18

/src/gdal/gcore/gdalnodatamaskband.cpp
Line
Count
Source (jump to first uncovered line)
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 <cmath>
20
#include <cstring>
21
#include <utility>
22
23
#include "cpl_conv.h"
24
#include "cpl_error.h"
25
#include "cpl_vsi.h"
26
#include "gdal.h"
27
#include "gdal_priv_templates.hpp"
28
29
//! @cond Doxygen_Suppress
30
/************************************************************************/
31
/*                        GDALNoDataMaskBand()                          */
32
/************************************************************************/
33
34
GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn)
35
0
    : m_poParent(poParentIn)
36
0
{
37
0
    poDS = nullptr;
38
0
    nBand = 0;
39
40
0
    nRasterXSize = m_poParent->GetXSize();
41
0
    nRasterYSize = m_poParent->GetYSize();
42
43
0
    eDataType = GDT_Byte;
44
0
    m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
45
46
0
    const auto eParentDT = m_poParent->GetRasterDataType();
47
0
    if (eParentDT == GDT_Int64)
48
0
        m_nNoDataValueInt64 = m_poParent->GetNoDataValueAsInt64();
49
0
    else if (eParentDT == GDT_UInt64)
50
0
        m_nNoDataValueUInt64 = m_poParent->GetNoDataValueAsUInt64();
51
0
    else
52
0
        m_dfNoDataValue = m_poParent->GetNoDataValue();
53
0
}
54
55
/************************************************************************/
56
/*                        GDALNoDataMaskBand()                          */
57
/************************************************************************/
58
59
GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn,
60
                                       double dfNoDataValue)
61
0
    : m_poParent(poParentIn)
62
0
{
63
0
    poDS = nullptr;
64
0
    nBand = 0;
65
66
0
    nRasterXSize = m_poParent->GetXSize();
67
0
    nRasterYSize = m_poParent->GetYSize();
68
69
0
    eDataType = GDT_Byte;
70
0
    m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
71
72
0
    const auto eParentDT = m_poParent->GetRasterDataType();
73
0
    if (eParentDT == GDT_Int64)
74
0
        m_nNoDataValueInt64 = static_cast<int64_t>(dfNoDataValue);
75
0
    else if (eParentDT == GDT_UInt64)
76
0
        m_nNoDataValueUInt64 = static_cast<uint64_t>(dfNoDataValue);
77
0
    else
78
0
        m_dfNoDataValue = dfNoDataValue;
79
0
}
80
81
/************************************************************************/
82
/*                       ~GDALNoDataMaskBand()                          */
83
/************************************************************************/
84
85
0
GDALNoDataMaskBand::~GDALNoDataMaskBand() = default;
86
87
/************************************************************************/
88
/*                          GetWorkDataType()                           */
89
/************************************************************************/
90
91
static GDALDataType GetWorkDataType(GDALDataType eDataType)
92
0
{
93
0
    GDALDataType eWrkDT = GDT_Unknown;
94
0
    switch (eDataType)
95
0
    {
96
0
        case GDT_Byte:
97
0
            eWrkDT = GDT_Byte;
98
0
            break;
99
100
0
        case GDT_Int16:
101
0
            eWrkDT = GDT_Int16;
102
0
            break;
103
104
0
        case GDT_UInt16:
105
0
            eWrkDT = GDT_UInt16;
106
0
            break;
107
108
0
        case GDT_UInt32:
109
0
            eWrkDT = GDT_UInt32;
110
0
            break;
111
112
0
        case GDT_Int8:
113
0
        case GDT_Int32:
114
0
        case GDT_CInt16:
115
0
        case GDT_CInt32:
116
0
            eWrkDT = GDT_Int32;
117
0
            break;
118
119
0
        case GDT_Float16:
120
0
        case GDT_CFloat16:
121
0
        case GDT_Float32:
122
0
        case GDT_CFloat32:
123
0
            eWrkDT = GDT_Float32;
124
0
            break;
125
126
0
        case GDT_Float64:
127
0
        case GDT_CFloat64:
128
0
            eWrkDT = GDT_Float64;
129
0
            break;
130
131
0
        case GDT_Int64:
132
0
        case GDT_UInt64:
133
0
            eWrkDT = eDataType;
134
0
            break;
135
136
0
        case GDT_Unknown:
137
0
        case GDT_TypeCount:
138
0
            CPLAssert(false);
139
0
            eWrkDT = GDT_Float64;
140
0
            break;
141
0
    }
142
0
    return eWrkDT;
143
0
}
144
145
/************************************************************************/
146
/*                          IsNoDataInRange()                           */
147
/************************************************************************/
148
149
bool GDALNoDataMaskBand::IsNoDataInRange(double dfNoDataValue,
150
                                         GDALDataType eDataTypeIn)
151
0
{
152
0
    GDALDataType eWrkDT = GetWorkDataType(eDataTypeIn);
153
0
    switch (eWrkDT)
154
0
    {
155
0
        case GDT_Byte:
156
0
        {
157
0
            return GDALIsValueInRange<GByte>(dfNoDataValue);
158
0
        }
159
160
0
        case GDT_Int16:
161
0
        {
162
0
            return GDALIsValueInRange<GInt16>(dfNoDataValue);
163
0
        }
164
165
0
        case GDT_UInt16:
166
0
        {
167
0
            return GDALIsValueInRange<GUInt16>(dfNoDataValue);
168
0
        }
169
170
0
        case GDT_UInt32:
171
0
        {
172
0
            return GDALIsValueInRange<GUInt32>(dfNoDataValue);
173
0
        }
174
0
        case GDT_Int32:
175
0
        {
176
0
            return GDALIsValueInRange<GInt32>(dfNoDataValue);
177
0
        }
178
179
0
        case GDT_UInt64:
180
0
        {
181
0
            return GDALIsValueInRange<uint64_t>(dfNoDataValue);
182
0
        }
183
184
0
        case GDT_Int64:
185
0
        {
186
0
            return GDALIsValueInRange<int64_t>(dfNoDataValue);
187
0
        }
188
189
0
        case GDT_Float16:
190
0
        {
191
0
            return std::isnan(dfNoDataValue) || std::isinf(dfNoDataValue) ||
192
0
                   GDALIsValueInRange<GFloat16>(dfNoDataValue);
193
0
        }
194
195
0
        case GDT_Float32:
196
0
        {
197
0
            return std::isnan(dfNoDataValue) || std::isinf(dfNoDataValue) ||
198
0
                   GDALIsValueInRange<float>(dfNoDataValue);
199
0
        }
200
201
0
        case GDT_Float64:
202
0
        {
203
0
            return true;
204
0
        }
205
206
0
        default:
207
0
            CPLAssert(false);
208
0
            return false;
209
0
    }
210
0
}
211
212
/************************************************************************/
213
/*                             IReadBlock()                             */
214
/************************************************************************/
215
216
CPLErr GDALNoDataMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff,
217
                                      void *pImage)
218
219
0
{
220
0
    const int nXOff = nXBlockOff * nBlockXSize;
221
0
    const int nXSizeRequest = std::min(nBlockXSize, nRasterXSize - nXOff);
222
0
    const int nYOff = nYBlockOff * nBlockYSize;
223
0
    const int nYSizeRequest = std::min(nBlockYSize, nRasterYSize - nYOff);
224
225
0
    if (nBlockXSize != nXSizeRequest || nBlockYSize != nYSizeRequest)
226
0
    {
227
0
        memset(pImage, 0, static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
228
0
    }
229
230
0
    GDALRasterIOExtraArg sExtraArg;
231
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
232
0
    return IRasterIO(GF_Read, nXOff, nYOff, nXSizeRequest, nYSizeRequest,
233
0
                     pImage, nXSizeRequest, nYSizeRequest, GDT_Byte, 1,
234
0
                     nBlockXSize, &sExtraArg);
235
0
}
236
237
/************************************************************************/
238
/*                            SetZeroOr255()                            */
239
/************************************************************************/
240
241
#if (defined(__GNUC__) && !defined(__clang__))
242
__attribute__((optimize("tree-vectorize")))
243
#endif
244
static void
245
SetZeroOr255(GByte *pabyDestAndSrc, size_t nBufSize, GByte byNoData)
246
0
{
247
0
    for (size_t i = 0; i < nBufSize; ++i)
248
0
    {
249
0
        pabyDestAndSrc[i] = (pabyDestAndSrc[i] == byNoData) ? 0 : 255;
250
0
    }
251
0
}
252
253
template <class T>
254
#if (defined(__GNUC__) && !defined(__clang__))
255
__attribute__((optimize("tree-vectorize")))
256
#endif
257
static void
258
SetZeroOr255(GByte *pabyDest, const T *panSrc, size_t nBufSize, T nNoData)
259
0
{
260
0
    for (size_t i = 0; i < nBufSize; ++i)
261
0
    {
262
0
        pabyDest[i] = (panSrc[i] == nNoData) ? 0 : 255;
263
0
    }
264
0
}
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<unsigned char>(unsigned char*, unsigned char const*, unsigned long, unsigned char)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<short>(unsigned char*, short const*, unsigned long, short)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<unsigned short>(unsigned char*, unsigned short const*, unsigned long, unsigned short)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<unsigned int>(unsigned char*, unsigned int const*, unsigned long, unsigned int)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<int>(unsigned char*, int const*, unsigned long, int)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<long>(unsigned char*, long const*, unsigned long, long)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<unsigned long>(unsigned char*, unsigned long const*, unsigned long, unsigned long)
265
266
template <class T>
267
static void SetZeroOr255(GByte *pabyDest, const T *panSrc, int nBufXSize,
268
                         int nBufYSize, GSpacing nPixelSpace,
269
                         GSpacing nLineSpace, T nNoData)
270
0
{
271
0
    if (nPixelSpace == 1 && nLineSpace == nBufXSize)
272
0
    {
273
0
        const size_t nBufSize = static_cast<size_t>(nBufXSize) * nBufYSize;
274
0
        SetZeroOr255(pabyDest, panSrc, nBufSize, nNoData);
275
0
    }
276
0
    else if (nPixelSpace == 1)
277
0
    {
278
0
        for (int iY = 0; iY < nBufYSize; iY++)
279
0
        {
280
0
            SetZeroOr255(pabyDest, panSrc, nBufXSize, nNoData);
281
0
            pabyDest += nLineSpace;
282
0
            panSrc += nBufXSize;
283
0
        }
284
0
    }
285
0
    else
286
0
    {
287
0
        size_t i = 0;
288
0
        for (int iY = 0; iY < nBufYSize; iY++)
289
0
        {
290
0
            GByte *pabyLineDest = pabyDest + iY * nLineSpace;
291
0
            for (int iX = 0; iX < nBufXSize; iX++)
292
0
            {
293
0
                *pabyLineDest = (panSrc[i] == nNoData) ? 0 : 255;
294
0
                ++i;
295
0
                pabyLineDest += nPixelSpace;
296
0
            }
297
0
        }
298
0
    }
299
0
}
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<unsigned char>(unsigned char*, unsigned char const*, int, int, long long, long long, unsigned char)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<short>(unsigned char*, short const*, int, int, long long, long long, short)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<unsigned short>(unsigned char*, unsigned short const*, int, int, long long, long long, unsigned short)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<unsigned int>(unsigned char*, unsigned int const*, int, int, long long, long long, unsigned int)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<int>(unsigned char*, int const*, int, int, long long, long long, int)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<long>(unsigned char*, long const*, int, int, long long, long long, long)
Unexecuted instantiation: gdalnodatamaskband.cpp:void SetZeroOr255<unsigned long>(unsigned char*, unsigned long const*, int, int, long long, long long, unsigned long)
300
301
/************************************************************************/
302
/*                             IRasterIO()                              */
303
/************************************************************************/
304
305
CPLErr GDALNoDataMaskBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
306
                                     int nXSize, int nYSize, void *pData,
307
                                     int nBufXSize, int nBufYSize,
308
                                     GDALDataType eBufType,
309
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
310
                                     GDALRasterIOExtraArg *psExtraArg)
311
0
{
312
0
    if (eRWFlag != GF_Read)
313
0
    {
314
0
        return CE_Failure;
315
0
    }
316
0
    const auto eParentDT = m_poParent->GetRasterDataType();
317
0
    const GDALDataType eWrkDT = GetWorkDataType(eParentDT);
318
319
    // Optimization in common use case (#4488).
320
    // This avoids triggering the block cache on this band, which helps
321
    // reducing the global block cache consumption.
322
0
    if (eBufType == GDT_Byte && eWrkDT == GDT_Byte)
323
0
    {
324
0
        const CPLErr eErr = m_poParent->RasterIO(
325
0
            GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
326
0
            eBufType, nPixelSpace, nLineSpace, psExtraArg);
327
0
        if (eErr != CE_None)
328
0
            return eErr;
329
330
0
        GByte *pabyData = static_cast<GByte *>(pData);
331
0
        const GByte byNoData = static_cast<GByte>(m_dfNoDataValue);
332
333
0
        if (nPixelSpace == 1 && nLineSpace == nBufXSize)
334
0
        {
335
0
            const size_t nBufSize = static_cast<size_t>(nBufXSize) * nBufYSize;
336
0
            SetZeroOr255(pabyData, nBufSize, byNoData);
337
0
        }
338
0
        else
339
0
        {
340
0
            SetZeroOr255(pabyData, pabyData, nBufXSize, nBufYSize, nPixelSpace,
341
0
                         nLineSpace, byNoData);
342
0
        }
343
0
        return CE_None;
344
0
    }
345
346
0
    const auto AllocTempBufferOrFallback =
347
0
        [this, eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
348
0
         nBufYSize, eBufType, nPixelSpace, nLineSpace,
349
0
         psExtraArg](int nWrkDTSize) -> std::pair<CPLErr, void *>
350
0
    {
351
0
        auto poParentDS = m_poParent->GetDataset();
352
        // Check if we must simulate a memory allocation failure
353
        // Before checking the env variable, which is slightly expensive,
354
        // check first for a special dataset name, which is a cheap test.
355
0
        const char *pszOptVal =
356
0
            poParentDS && strcmp(poParentDS->GetDescription(), "__debug__") == 0
357
0
                ? CPLGetConfigOption(
358
0
                      "GDAL_SIMUL_MEM_ALLOC_FAILURE_NODATA_MASK_BAND", "NO")
359
0
                : "NO";
360
0
        const bool bSimulMemAllocFailure =
361
0
            EQUAL(pszOptVal, "ALWAYS") ||
362
0
            (CPLTestBool(pszOptVal) &&
363
0
             GDALMajorObject::GetMetadataItem(__func__, "__INTERNAL__") ==
364
0
                 nullptr);
365
0
        void *pTemp = nullptr;
366
0
        if (!bSimulMemAllocFailure)
367
0
        {
368
0
            CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
369
0
            pTemp = VSI_MALLOC3_VERBOSE(nWrkDTSize, nBufXSize, nBufYSize);
370
0
        }
371
0
        if (!pTemp)
372
0
        {
373
0
            const bool bAllocHasAlreadyFailed =
374
0
                GDALMajorObject::GetMetadataItem(__func__, "__INTERNAL__") !=
375
0
                nullptr;
376
0
            CPLError(bAllocHasAlreadyFailed ? CE_Failure : CE_Warning,
377
0
                     CPLE_OutOfMemory,
378
0
                     "GDALNoDataMaskBand::IRasterIO(): cannot allocate %d x %d "
379
0
                     "x %d bytes%s",
380
0
                     nBufXSize, nBufYSize, nWrkDTSize,
381
0
                     bAllocHasAlreadyFailed
382
0
                         ? ""
383
0
                         : ". Falling back to block-based approach");
384
0
            if (bAllocHasAlreadyFailed)
385
0
                return std::pair(CE_Failure, nullptr);
386
            // Sets a metadata item to prevent potential infinite recursion
387
0
            GDALMajorObject::SetMetadataItem(__func__, "IN", "__INTERNAL__");
388
0
            const CPLErr eErr = GDALRasterBand::IRasterIO(
389
0
                eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
390
0
                nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
391
0
            GDALMajorObject::SetMetadataItem(__func__, nullptr, "__INTERNAL__");
392
0
            return std::pair(eErr, nullptr);
393
0
        }
394
0
        return std::pair(CE_None, pTemp);
395
0
    };
396
397
0
    if (eBufType == GDT_Byte)
398
0
    {
399
0
        const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
400
0
        auto [eErr, pTemp] = AllocTempBufferOrFallback(nWrkDTSize);
401
0
        if (!pTemp)
402
0
            return eErr;
403
404
0
        eErr = m_poParent->RasterIO(
405
0
            GF_Read, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize, nBufYSize,
406
0
            eWrkDT, nWrkDTSize, static_cast<GSpacing>(nBufXSize) * nWrkDTSize,
407
0
            psExtraArg);
408
0
        if (eErr != CE_None)
409
0
        {
410
0
            VSIFree(pTemp);
411
0
            return eErr;
412
0
        }
413
414
0
        const bool bIsNoDataNan = std::isnan(m_dfNoDataValue) != 0;
415
0
        GByte *pabyDest = static_cast<GByte *>(pData);
416
417
        /* --------------------------------------------------------------------
418
         */
419
        /*      Process different cases. */
420
        /* --------------------------------------------------------------------
421
         */
422
0
        switch (eWrkDT)
423
0
        {
424
0
            case GDT_Int16:
425
0
            {
426
0
                const auto nNoData = static_cast<int16_t>(m_dfNoDataValue);
427
0
                const auto *panSrc = static_cast<const int16_t *>(pTemp);
428
0
                SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
429
0
                             nPixelSpace, nLineSpace, nNoData);
430
0
            }
431
0
            break;
432
433
0
            case GDT_UInt16:
434
0
            {
435
0
                const auto nNoData = static_cast<uint16_t>(m_dfNoDataValue);
436
0
                const auto *panSrc = static_cast<const uint16_t *>(pTemp);
437
0
                SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
438
0
                             nPixelSpace, nLineSpace, nNoData);
439
0
            }
440
0
            break;
441
442
0
            case GDT_UInt32:
443
0
            {
444
0
                const auto nNoData = static_cast<GUInt32>(m_dfNoDataValue);
445
0
                const auto *panSrc = static_cast<const GUInt32 *>(pTemp);
446
0
                SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
447
0
                             nPixelSpace, nLineSpace, nNoData);
448
0
            }
449
0
            break;
450
451
0
            case GDT_Int32:
452
0
            {
453
0
                const auto nNoData = static_cast<GInt32>(m_dfNoDataValue);
454
0
                const auto *panSrc = static_cast<const GInt32 *>(pTemp);
455
0
                SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
456
0
                             nPixelSpace, nLineSpace, nNoData);
457
0
            }
458
0
            break;
459
460
0
            case GDT_Float32:
461
0
            {
462
0
                const float fNoData = static_cast<float>(m_dfNoDataValue);
463
0
                const float *pafSrc = static_cast<const float *>(pTemp);
464
465
0
                size_t i = 0;
466
0
                for (int iY = 0; iY < nBufYSize; iY++)
467
0
                {
468
0
                    GByte *pabyLineDest = pabyDest + iY * nLineSpace;
469
0
                    for (int iX = 0; iX < nBufXSize; iX++)
470
0
                    {
471
0
                        const float fVal = pafSrc[i];
472
0
                        if (bIsNoDataNan && std::isnan(fVal))
473
0
                            *pabyLineDest = 0;
474
0
                        else if (ARE_REAL_EQUAL(fVal, fNoData))
475
0
                            *pabyLineDest = 0;
476
0
                        else
477
0
                            *pabyLineDest = 255;
478
0
                        ++i;
479
0
                        pabyLineDest += nPixelSpace;
480
0
                    }
481
0
                }
482
0
            }
483
0
            break;
484
485
0
            case GDT_Float64:
486
0
            {
487
0
                const double *padfSrc = static_cast<const double *>(pTemp);
488
489
0
                size_t i = 0;
490
0
                for (int iY = 0; iY < nBufYSize; iY++)
491
0
                {
492
0
                    GByte *pabyLineDest = pabyDest + iY * nLineSpace;
493
0
                    for (int iX = 0; iX < nBufXSize; iX++)
494
0
                    {
495
0
                        const double dfVal = padfSrc[i];
496
0
                        if (bIsNoDataNan && std::isnan(dfVal))
497
0
                            *pabyLineDest = 0;
498
0
                        else if (ARE_REAL_EQUAL(dfVal, m_dfNoDataValue))
499
0
                            *pabyLineDest = 0;
500
0
                        else
501
0
                            *pabyLineDest = 255;
502
0
                        ++i;
503
0
                        pabyLineDest += nPixelSpace;
504
0
                    }
505
0
                }
506
0
            }
507
0
            break;
508
509
0
            case GDT_Int64:
510
0
            {
511
0
                const auto *panSrc = static_cast<const int64_t *>(pTemp);
512
0
                SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
513
0
                             nPixelSpace, nLineSpace, m_nNoDataValueInt64);
514
0
            }
515
0
            break;
516
517
0
            case GDT_UInt64:
518
0
            {
519
0
                const auto *panSrc = static_cast<const uint64_t *>(pTemp);
520
0
                SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
521
0
                             nPixelSpace, nLineSpace, m_nNoDataValueUInt64);
522
0
            }
523
0
            break;
524
525
0
            default:
526
0
                CPLAssert(false);
527
0
                break;
528
0
        }
529
530
0
        VSIFree(pTemp);
531
0
        return CE_None;
532
0
    }
533
534
    // Output buffer is non-Byte. Ask for Byte and expand to user requested
535
    // type
536
0
    auto [eErr, pTemp] = AllocTempBufferOrFallback(sizeof(GByte));
537
0
    if (!pTemp)
538
0
        return eErr;
539
540
0
    eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize,
541
0
                     nBufYSize, GDT_Byte, 1, nBufXSize, psExtraArg);
542
0
    if (eErr != CE_None)
543
0
    {
544
0
        VSIFree(pTemp);
545
0
        return eErr;
546
0
    }
547
548
0
    for (int iY = 0; iY < nBufYSize; iY++)
549
0
    {
550
0
        GDALCopyWords64(
551
0
            static_cast<GByte *>(pTemp) + static_cast<size_t>(iY) * nBufXSize,
552
0
            GDT_Byte, 1, static_cast<GByte *>(pData) + iY * nLineSpace,
553
0
            eBufType, static_cast<int>(nPixelSpace), nBufXSize);
554
0
    }
555
0
    VSIFree(pTemp);
556
0
    return CE_None;
557
0
}
558
559
/************************************************************************/
560
/*                   EmitErrorMessageIfWriteNotSupported()              */
561
/************************************************************************/
562
563
bool GDALNoDataMaskBand::EmitErrorMessageIfWriteNotSupported(
564
    const char *pszCaller) const
565
0
{
566
0
    ReportError(CE_Failure, CPLE_NoWriteAccess,
567
0
                "%s: attempt to write to a nodata implicit mask band.",
568
0
                pszCaller);
569
570
0
    return true;
571
0
}
572
573
//! @endcond