Coverage Report

Created: 2025-06-13 06:18

/src/gdal/gcore/gdalnodatavaluesmaskband.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Implementation of GDALNoDataValuesMaskBand, a class implementing
5
 *           a default band mask based on the NODATA_VALUES metadata item.
6
 *           A pixel is considered nodata in all bands if and only if all bands
7
 *           match the corresponding value in the NODATA_VALUES tuple
8
 * Author:   Even Rouault, <even dot rouault at spatialys.com>
9
 *
10
 ******************************************************************************
11
 * Copyright (c) 2008-2009, Even Rouault <even dot rouault at spatialys.com>
12
 *
13
 * SPDX-License-Identifier: MIT
14
 ****************************************************************************/
15
16
#include "cpl_port.h"
17
#include "gdal_priv.h"
18
19
#include <cstring>
20
21
#include "cpl_conv.h"
22
#include "cpl_error.h"
23
#include "cpl_string.h"
24
#include "cpl_vsi.h"
25
#include "gdal.h"
26
27
//! @cond Doxygen_Suppress
28
/************************************************************************/
29
/*                   GDALNoDataValuesMaskBand()                         */
30
/************************************************************************/
31
32
GDALNoDataValuesMaskBand::GDALNoDataValuesMaskBand(GDALDataset *poDSIn)
33
0
    : padfNodataValues(nullptr)
34
0
{
35
0
    const char *pszNoDataValues = poDSIn->GetMetadataItem("NODATA_VALUES");
36
0
    char **papszNoDataValues =
37
0
        CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
38
39
0
    padfNodataValues = static_cast<double *>(
40
0
        CPLMalloc(sizeof(double) * poDSIn->GetRasterCount()));
41
0
    for (int i = 0; i < poDSIn->GetRasterCount(); ++i)
42
0
    {
43
0
        padfNodataValues[i] = CPLAtof(papszNoDataValues[i]);
44
0
    }
45
46
0
    CSLDestroy(papszNoDataValues);
47
48
0
    poDS = poDSIn;
49
0
    nBand = 0;
50
51
0
    nRasterXSize = poDS->GetRasterXSize();
52
0
    nRasterYSize = poDS->GetRasterYSize();
53
54
0
    eDataType = GDT_Byte;
55
0
    poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
56
0
}
57
58
/************************************************************************/
59
/*                    ~GDALNoDataValuesMaskBand()                       */
60
/************************************************************************/
61
62
GDALNoDataValuesMaskBand::~GDALNoDataValuesMaskBand()
63
64
0
{
65
0
    CPLFree(padfNodataValues);
66
0
}
67
68
/************************************************************************/
69
/*                            FillOutBuffer()                           */
70
/************************************************************************/
71
72
template <class T>
73
static void FillOutBuffer(GPtrDiff_t nBlockOffsetPixels, int nBands,
74
                          const void *pabySrc, const double *padfNodataValues,
75
                          void *pImage)
76
0
{
77
0
    T *paNoData = static_cast<T *>(CPLMalloc(nBands * sizeof(T)));
78
0
    for (int iBand = 0; iBand < nBands; ++iBand)
79
0
    {
80
0
        paNoData[iBand] = static_cast<T>(padfNodataValues[iBand]);
81
0
    }
82
83
0
    for (GPtrDiff_t i = 0; i < nBlockOffsetPixels; i++)
84
0
    {
85
0
        int nCountNoData = 0;
86
0
        for (int iBand = 0; iBand < nBands; ++iBand)
87
0
        {
88
0
            if (static_cast<const T *>(
89
0
                    pabySrc)[i + iBand * nBlockOffsetPixels] == paNoData[iBand])
90
0
                ++nCountNoData;
91
0
        }
92
0
        static_cast<GByte *>(pImage)[i] = nCountNoData == nBands ? 0 : 255;
93
0
    }
94
95
0
    CPLFree(paNoData);
96
0
}
Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<unsigned char>(long long, int, void const*, double const*, void*)
Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<unsigned int>(long long, int, void const*, double const*, void*)
Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<int>(long long, int, void const*, double const*, void*)
Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<float>(long long, int, void const*, double const*, void*)
Unexecuted instantiation: gdalnodatavaluesmaskband.cpp:void FillOutBuffer<double>(long long, int, void const*, double const*, void*)
97
98
/************************************************************************/
99
/*                             IReadBlock()                             */
100
/************************************************************************/
101
102
CPLErr GDALNoDataValuesMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff,
103
                                            void *pImage)
104
105
0
{
106
0
    GDALDataType eWrkDT = GDT_Unknown;
107
108
    /* -------------------------------------------------------------------- */
109
    /*      Decide on a working type.                                       */
110
    /* -------------------------------------------------------------------- */
111
0
    switch (poDS->GetRasterBand(1)->GetRasterDataType())
112
0
    {
113
0
        case GDT_Byte:
114
0
            eWrkDT = GDT_Byte;
115
0
            break;
116
117
0
        case GDT_UInt16:
118
0
        case GDT_UInt32:
119
0
            eWrkDT = GDT_UInt32;
120
0
            break;
121
122
0
        case GDT_Int8:
123
0
        case GDT_Int16:
124
0
        case GDT_Int32:
125
0
        case GDT_CInt16:
126
0
        case GDT_CInt32:
127
0
            eWrkDT = GDT_Int32;
128
0
            break;
129
130
0
        case GDT_Float16:
131
0
        case GDT_CFloat16:
132
0
        case GDT_Float32:
133
0
        case GDT_CFloat32:
134
0
            eWrkDT = GDT_Float32;
135
0
            break;
136
137
0
        case GDT_Float64:
138
0
        case GDT_CFloat64:
139
0
            eWrkDT = GDT_Float64;
140
0
            break;
141
142
0
        case GDT_Int64:
143
0
        case GDT_UInt64:
144
            // Lossy mapping...
145
0
            eWrkDT = GDT_Float64;
146
0
            break;
147
148
0
        case GDT_Unknown:
149
0
        case GDT_TypeCount:
150
0
            CPLAssert(false);
151
0
            eWrkDT = GDT_Float64;
152
0
            break;
153
0
    }
154
155
    /* -------------------------------------------------------------------- */
156
    /*      Read the image data.                                            */
157
    /* -------------------------------------------------------------------- */
158
0
    const int nBands = poDS->GetRasterCount();
159
0
    const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
160
0
    GByte *pabySrc = static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
161
0
        cpl::fits_on<int>(nBands * nWrkDTSize), nBlockXSize, nBlockYSize));
162
0
    if (pabySrc == nullptr)
163
0
    {
164
0
        return CE_Failure;
165
0
    }
166
167
0
    int nXSizeRequest = 0;
168
0
    int nYSizeRequest = 0;
169
0
    GetActualBlockSize(nXBlockOff, nYBlockOff, &nXSizeRequest, &nYSizeRequest);
170
171
0
    if (nXSizeRequest != nBlockXSize || nYSizeRequest != nBlockYSize)
172
0
    {
173
        // memset the whole buffer to avoid Valgrind warnings in case we can't
174
        // fetch a full block.
175
0
        memset(pabySrc, 0,
176
0
               static_cast<size_t>(nBands) * nWrkDTSize * nBlockXSize *
177
0
                   nBlockYSize);
178
0
    }
179
180
0
    const GPtrDiff_t nBlockOffsetPixels =
181
0
        static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
182
0
    const GPtrDiff_t nBandOffsetByte = nWrkDTSize * nBlockOffsetPixels;
183
0
    for (int iBand = 0; iBand < nBands; ++iBand)
184
0
    {
185
0
        const CPLErr eErr = poDS->GetRasterBand(iBand + 1)->RasterIO(
186
0
            GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize,
187
0
            nXSizeRequest, nYSizeRequest, pabySrc + iBand * nBandOffsetByte,
188
0
            nXSizeRequest, nYSizeRequest, eWrkDT, 0,
189
0
            static_cast<GSpacing>(nBlockXSize) * nWrkDTSize, nullptr);
190
0
        if (eErr != CE_None)
191
0
            return eErr;
192
0
    }
193
194
    /* -------------------------------------------------------------------- */
195
    /*      Process different cases.                                        */
196
    /* -------------------------------------------------------------------- */
197
0
    switch (eWrkDT)
198
0
    {
199
0
        case GDT_Byte:
200
0
        {
201
0
            FillOutBuffer<GByte>(nBlockOffsetPixels, nBands, pabySrc,
202
0
                                 padfNodataValues, pImage);
203
0
        }
204
0
        break;
205
206
0
        case GDT_UInt32:
207
0
        {
208
0
            FillOutBuffer<GUInt32>(nBlockOffsetPixels, nBands, pabySrc,
209
0
                                   padfNodataValues, pImage);
210
0
        }
211
0
        break;
212
213
0
        case GDT_Int32:
214
0
        {
215
0
            FillOutBuffer<GInt32>(nBlockOffsetPixels, nBands, pabySrc,
216
0
                                  padfNodataValues, pImage);
217
0
        }
218
0
        break;
219
220
0
        case GDT_Float32:
221
0
        {
222
0
            FillOutBuffer<float>(nBlockOffsetPixels, nBands, pabySrc,
223
0
                                 padfNodataValues, pImage);
224
0
        }
225
0
        break;
226
227
0
        case GDT_Float64:
228
0
        {
229
0
            FillOutBuffer<double>(nBlockOffsetPixels, nBands, pabySrc,
230
0
                                  padfNodataValues, pImage);
231
0
        }
232
0
        break;
233
234
0
        default:
235
0
            CPLAssert(false);
236
0
            break;
237
0
    }
238
239
0
    CPLFree(pabySrc);
240
241
0
    return CE_None;
242
0
}
243
244
/************************************************************************/
245
/*                   EmitErrorMessageIfWriteNotSupported()              */
246
/************************************************************************/
247
248
bool GDALNoDataValuesMaskBand::EmitErrorMessageIfWriteNotSupported(
249
    const char *pszCaller) const
250
0
{
251
0
    ReportError(CE_Failure, CPLE_NoWriteAccess,
252
0
                "%s: attempt to write to a nodata implicit mask band.",
253
0
                pszCaller);
254
255
0
    return true;
256
0
}
257
258
//! @endcond