Coverage Report

Created: 2026-08-11 08:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/wcs/wcsrasterband.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  WCS Client Driver
4
 * Purpose:  Implementation of RasterBand classes for WCS.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2006, Frank Warmerdam
9
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_http.h"
15
#include "gdal_pam.h"
16
#include "gdal_rasterblock.h"
17
18
#include <algorithm>
19
#include <cassert>
20
21
#include "wcsdataset.h"
22
#include "wcsrasterband.h"
23
24
/************************************************************************/
25
/*                           WCSRasterBand()                            */
26
/************************************************************************/
27
28
WCSRasterBand::WCSRasterBand(WCSDataset *poDSIn, int nBandIn, int iOverviewIn)
29
0
    : iOverview(iOverviewIn),
30
0
      nResFactor(1 << (iOverviewIn + 1)),  // iOverview == -1 is base layer
31
0
      poODS(poDSIn), nOverviewCount(0), papoOverviews(nullptr)
32
0
{
33
0
    poDS = poDSIn;
34
0
    nBand = nBandIn;
35
36
0
    eDataType = GDALGetDataTypeByName(
37
0
        CPLGetXMLValue(poDSIn->psService, "BandType", "Byte"));
38
39
    /* -------------------------------------------------------------------- */
40
    /*      Establish resolution reduction for this overview level.         */
41
    /* -------------------------------------------------------------------- */
42
43
    /* -------------------------------------------------------------------- */
44
    /*      Establish block size.                                           */
45
    /* -------------------------------------------------------------------- */
46
0
    nRasterXSize = poDS->GetRasterXSize() / nResFactor;
47
0
    nRasterYSize = poDS->GetRasterYSize() / nResFactor;
48
49
0
    nBlockXSize = atoi(CPLGetXMLValue(poDSIn->psService, "BlockXSize", "0"));
50
0
    nBlockYSize = atoi(CPLGetXMLValue(poDSIn->psService, "BlockYSize", "0"));
51
52
0
    if (nBlockXSize < 1)
53
0
    {
54
0
        if (nRasterXSize > 1800)
55
0
            nBlockXSize = 1024;
56
0
        else
57
0
            nBlockXSize = nRasterXSize;
58
0
    }
59
60
0
    if (nBlockYSize < 1)
61
0
    {
62
0
        if (nRasterYSize > 900)
63
0
            nBlockYSize = 512;
64
0
        else
65
0
            nBlockYSize = nRasterYSize;
66
0
    }
67
68
    /* -------------------------------------------------------------------- */
69
    /*      If this is the base layer, create the overview layers.          */
70
    /* -------------------------------------------------------------------- */
71
0
    if (iOverview == -1)
72
0
    {
73
0
        nOverviewCount =
74
0
            atoi(CPLGetXMLValue(poODS->psService, "OverviewCount", "-1"));
75
0
        if (nOverviewCount < 0)
76
0
        {
77
0
            for (nOverviewCount = 0; (std::max(nRasterXSize, nRasterYSize) /
78
0
                                      (1 << nOverviewCount)) > 900;
79
0
                 nOverviewCount++)
80
0
            {
81
0
            }
82
0
        }
83
0
        else if (nOverviewCount > 30)
84
0
        {
85
            /* There's no reason to have more than 30 overviews, because */
86
            /* 2^(30+1) overflows a int32 */
87
0
            nOverviewCount = 30;
88
0
        }
89
90
0
        papoOverviews =
91
0
            (WCSRasterBand **)CPLCalloc(nOverviewCount, sizeof(void *));
92
93
0
        for (int i = 0; i < nOverviewCount; i++)
94
0
            papoOverviews[i] = new WCSRasterBand(poODS, nBand, i);
95
0
    }
96
0
}
97
98
/************************************************************************/
99
/*                           ~WCSRasterBand()                           */
100
/************************************************************************/
101
102
WCSRasterBand::~WCSRasterBand()
103
104
0
{
105
0
    FlushCache(true);
106
107
0
    if (nOverviewCount > 0)
108
0
    {
109
0
        for (int i = 0; i < nOverviewCount; i++)
110
0
            delete papoOverviews[i];
111
112
0
        CPLFree(papoOverviews);
113
0
    }
114
0
}
115
116
/************************************************************************/
117
/*                             IReadBlock()                             */
118
/************************************************************************/
119
120
CPLErr WCSRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
121
122
0
{
123
0
    CPLErr eErr;
124
0
    CPLHTTPResult *psResult = nullptr;
125
126
    // if INTERLEAVE is set to PIXEL, then we'll request all bands.
127
    // That is necessary at least with MapServer, which seems to often
128
    // return all bands instead of requested.
129
    // todo: in 2.0.1 the band list in this dataset may be user-defined
130
131
0
    int band_count = 1;
132
0
    if (EQUAL(CPLGetXMLValue(poODS->psService, GDALMD_INTERLEAVE, ""), "PIXEL"))
133
0
    {
134
0
        band_count = 0;
135
0
    }
136
137
0
    eErr = poODS->GetCoverage(
138
0
        nBlockXOff * nBlockXSize * nResFactor,
139
0
        nBlockYOff * nBlockYSize * nResFactor, nBlockXSize * nResFactor,
140
0
        nBlockYSize * nResFactor, nBlockXSize, nBlockYSize, band_count, &nBand,
141
0
        nullptr, &psResult);
142
0
    if (eErr != CE_None)
143
0
        return eErr;
144
145
    /* -------------------------------------------------------------------- */
146
    /*      Try and open result as a dataset.                               */
147
    /* -------------------------------------------------------------------- */
148
0
    GDALDataset *poTileDS = poODS->GDALOpenResult(psResult);
149
150
0
    if (poTileDS == nullptr)
151
0
        return CE_Failure;
152
153
    /* -------------------------------------------------------------------- */
154
    /*      Verify configuration.                                           */
155
    /* -------------------------------------------------------------------- */
156
0
    if (poTileDS->GetRasterXSize() != nBlockXSize ||
157
0
        poTileDS->GetRasterYSize() != nBlockYSize)
158
0
    {
159
0
        CPLError(CE_Failure, CPLE_AppDefined,
160
0
                 "Returned tile does not match expected configuration.\n"
161
0
                 "Got %dx%d instead of %dx%d.",
162
0
                 poTileDS->GetRasterXSize(), poTileDS->GetRasterYSize(),
163
0
                 nBlockXSize, nBlockYSize);
164
0
        delete poTileDS;
165
0
        return CE_Failure;
166
0
    }
167
168
0
    if (band_count == 1 &&
169
0
        ((!poODS->osBandIdentifier.empty() &&
170
0
          poTileDS->GetRasterCount() != 1) ||
171
0
         (poODS->osBandIdentifier.empty() &&
172
0
          poTileDS->GetRasterCount() != poODS->GetRasterCount())))
173
0
    {
174
0
        CPLString msg;
175
0
        if (!poODS->osBandIdentifier.empty() && poTileDS->GetRasterCount() != 1)
176
0
        {
177
0
            msg.Printf("Got %d bands instead of one although the coverage has "
178
0
                       "band range type.\n",
179
0
                       poTileDS->GetRasterCount());
180
0
        }
181
0
        else
182
0
        {
183
0
            msg.Printf(
184
0
                "Response has %d bands while this dataset has %d bands.\n",
185
0
                poTileDS->GetRasterCount(), poODS->GetRasterCount());
186
0
        }
187
0
        CPLError(
188
0
            CE_Failure, CPLE_AppDefined,
189
0
            "Returned tile does not match expected band configuration.\n%s",
190
0
            msg.c_str());
191
0
        delete poTileDS;
192
0
        return CE_Failure;
193
0
    }
194
195
    /* -------------------------------------------------------------------- */
196
    /*      Process all bands of memory result, copying into pBuffer, or    */
197
    /*      pushing into cache for other bands.                             */
198
    /* -------------------------------------------------------------------- */
199
0
    int iBand;
200
0
    eErr = CE_None;
201
202
0
    for (iBand = 0; iBand < poTileDS->GetRasterCount() && eErr == CE_None;
203
0
         iBand++)
204
0
    {
205
0
        GDALRasterBand *poTileBand = poTileDS->GetRasterBand(iBand + 1);
206
207
0
        if (iBand + 1 == GetBand() ||
208
0
            (band_count == 1 && !poODS->osBandIdentifier.empty()))
209
0
        {
210
0
            eErr = poTileBand->RasterIO(GF_Read, 0, 0, nBlockXSize, nBlockYSize,
211
0
                                        pImage, nBlockXSize, nBlockYSize,
212
0
                                        eDataType, 0, 0, nullptr);
213
0
        }
214
0
        else
215
0
        {
216
0
            GDALRasterBand *poTargBand = poODS->GetRasterBand(iBand + 1);
217
218
0
            if (iOverview != -1)
219
0
                poTargBand = poTargBand->GetOverview(iOverview);
220
221
0
            assert(poTargBand);
222
0
#if defined(__GNUC__)
223
0
#pragma GCC diagnostic push
224
0
#pragma GCC diagnostic ignored "-Wnull-dereference"
225
0
#endif
226
0
            GDALRasterBlock *poBlock =
227
0
                poTargBand->GetLockedBlockRef(nBlockXOff, nBlockYOff, TRUE);
228
0
#if defined(__GNUC__)
229
0
#pragma GCC diagnostic pop
230
0
#endif
231
232
0
            if (poBlock != nullptr)
233
0
            {
234
0
                eErr = poTileBand->RasterIO(GF_Read, 0, 0, nBlockXSize,
235
0
                                            nBlockYSize, poBlock->GetDataRef(),
236
0
                                            nBlockXSize, nBlockYSize, eDataType,
237
0
                                            0, 0, nullptr);
238
0
                poBlock->DropLock();
239
0
            }
240
0
            else
241
0
                eErr = CE_Failure;
242
0
        }
243
0
    }
244
245
    /* -------------------------------------------------------------------- */
246
    /*      Cleanup                                                         */
247
    /* -------------------------------------------------------------------- */
248
0
    delete poTileDS;
249
250
0
    poODS->FlushMemoryResult();
251
252
0
    return eErr;
253
0
}
254
255
/************************************************************************/
256
/*                             IRasterIO()                              */
257
/************************************************************************/
258
259
CPLErr WCSRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
260
                                int nXSize, int nYSize, void *pData,
261
                                int nBufXSize, int nBufYSize,
262
                                GDALDataType eBufType, GSpacing nPixelSpace,
263
                                GSpacing nLineSpace,
264
                                GDALRasterIOExtraArg *psExtraArg)
265
266
0
{
267
0
    if ((poODS->nMaxCols > 0 && poODS->nMaxCols < nBufXSize) ||
268
0
        (poODS->nMaxRows > 0 && poODS->nMaxRows < nBufYSize))
269
0
        return CE_Failure;
270
271
0
    if (poODS->TestUseBlockIO(nXOff, nYOff, nXSize, nYSize, nBufXSize,
272
0
                              nBufYSize))
273
0
        return GDALPamRasterBand::IRasterIO(
274
0
            eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
275
0
            eBufType, nPixelSpace, nLineSpace, psExtraArg);
276
0
    else
277
0
        return poODS->DirectRasterIO(eRWFlag, nXOff * nResFactor,
278
0
                                     nYOff * nResFactor, nXSize * nResFactor,
279
0
                                     nYSize * nResFactor, pData, nBufXSize,
280
0
                                     nBufYSize, eBufType, 1, &nBand,
281
0
                                     nPixelSpace, nLineSpace, 0, psExtraArg);
282
0
}
283
284
/************************************************************************/
285
/*                           GetNoDataValue()                           */
286
/************************************************************************/
287
288
double WCSRasterBand::GetNoDataValue(int *pbSuccess)
289
290
0
{
291
0
    const char *pszSV =
292
0
        CPLGetXMLValue(poODS->psService, "NoDataValue", nullptr);
293
294
0
    if (pszSV == nullptr)
295
0
        return GDALPamRasterBand::GetNoDataValue(pbSuccess);
296
0
    else
297
0
    {
298
0
        if (pbSuccess)
299
0
            *pbSuccess = TRUE;
300
0
        return CPLAtof(pszSV);
301
0
    }
302
0
}
303
304
/************************************************************************/
305
/*                          GetOverviewCount()                          */
306
/************************************************************************/
307
308
int WCSRasterBand::GetOverviewCount()
309
310
0
{
311
0
    return nOverviewCount;
312
0
}
313
314
/************************************************************************/
315
/*                            GetOverview()                             */
316
/************************************************************************/
317
318
GDALRasterBand *WCSRasterBand::GetOverview(int iOverviewIn)
319
320
0
{
321
0
    if (iOverviewIn < 0 || iOverviewIn >= nOverviewCount)
322
0
        return nullptr;
323
0
    else
324
0
        return papoOverviews[iOverviewIn];
325
0
}