• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.69
/frmts/wms/gdalwmsrasterband.cpp
1
/******************************************************************************
2
 *
3
 * Project:  WMS Client Driver
4
 * Purpose:  GDALWMSRasterBand implementation.
5
 * Author:   Adam Nowacki, nowak@xpam.de
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2007, Adam Nowacki
9
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10
 * Copyright (c) 2017, Dmitry Baryshnikov, <polimax@mail.ru>
11
 * Copyright (c) 2017, NextGIS, <info@nextgis.com>
12
 *
13
 * SPDX-License-Identifier: MIT
14
 ****************************************************************************/
15

16
#include "wmsdriver.h"
17

18
#include <algorithm>
19

20
GDALWMSRasterBand::GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band,
6,959✔
21
                                     double scale)
6,959✔
22
    : m_parent_dataset(parent_dataset), m_scale(scale), m_overview(-1),
23
      m_color_interp(GCI_Undefined), m_nAdviseReadBX0(-1), m_nAdviseReadBY0(-1),
24
      m_nAdviseReadBX1(-1), m_nAdviseReadBY1(-1)
6,959✔
25
{
26
#ifdef DEBUG_VERBOSE
27
    printf("[%p] GDALWMSRasterBand::GDALWMSRasterBand(%p, %d, %f)\n", /*ok*/
28
           this, parent_dataset, band, scale);
29
#endif
30

31
    if (scale == 1.0)
6,959✔
32
        poDS = parent_dataset;
1,336✔
33
    else
34
        poDS = nullptr;
5,623✔
35
    if (parent_dataset->m_mini_driver_caps.m_overview_dim_computation_method ==
6,959✔
36
        OVERVIEW_ROUNDED)
37
    {
38
        nRasterXSize = static_cast<int>(
6,887✔
39
            m_parent_dataset->m_data_window.m_sx * scale + 0.5);
6,887✔
40
        nRasterYSize = static_cast<int>(
6,887✔
41
            m_parent_dataset->m_data_window.m_sy * scale + 0.5);
6,887✔
42
    }
43
    else
44
    {
45
        nRasterXSize =
72✔
46
            static_cast<int>(m_parent_dataset->m_data_window.m_sx * scale);
72✔
47
        nRasterYSize =
72✔
48
            static_cast<int>(m_parent_dataset->m_data_window.m_sy * scale);
72✔
49
    }
50
    nBand = band;
6,959✔
51
    eDataType = m_parent_dataset->m_data_type;
6,959✔
52
    nBlockXSize = m_parent_dataset->m_block_size_x;
6,959✔
53
    nBlockYSize = m_parent_dataset->m_block_size_y;
6,959✔
54
}
6,959✔
55

56
GDALWMSRasterBand::~GDALWMSRasterBand()
20,877✔
57
{
58
    while (!m_overviews.empty())
12,582✔
59
    {
60
        delete m_overviews.back();
5,623✔
61
        m_overviews.pop_back();
5,623✔
62
    }
63
}
13,918✔
64

65
// Request for x, y but all blocks between bx0-bx1 and by0-by1 should be read
66
CPLErr GDALWMSRasterBand::ReadBlocks(int x, int y, void *buffer, int bx0,
39✔
67
                                     int by0, int bx1, int by1, int advise_read)
68
{
69
    CPLErr ret = CE_None;
39✔
70

71
    // Get a vector of requests large enough for this call
72
    std::vector<WMSHTTPRequest> requests(static_cast<size_t>(bx1 - bx0 + 1) *
39✔
73
                                         (by1 - by0 + 1));
39✔
74

75
    size_t count = 0;  // How many requests are valid
39✔
76
    GDALWMSCache *cache = m_parent_dataset->m_cache;
39✔
77
    int offline = m_parent_dataset->m_offline_mode;
39✔
78
    const char *const *options = m_parent_dataset->GetHTTPRequestOpts();
39✔
79

80
    for (int iy = by0; iy <= by1; ++iy)
83✔
81
    {
82
        for (int ix = bx0; ix <= bx1; ++ix)
103✔
83
        {
84
            WMSHTTPRequest &request = requests[count];
59✔
85
            request.x = ix;
59✔
86
            request.y = iy;
59✔
87
            bool need_this_block = false;
59✔
88
            if (!advise_read)
59✔
89
            {
90
                for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
248✔
91
                {
92
                    if ((ix == x) && (iy == y) && (ib == nBand))
189✔
93
                    {
94
                        need_this_block = true;
39✔
95
                    }
96
                    else
97
                    {
98
                        GDALWMSRasterBand *band =
99
                            static_cast<GDALWMSRasterBand *>(
100
                                m_parent_dataset->GetRasterBand(ib));
150✔
101
                        if (m_overview >= 0)
150✔
102
                            band = static_cast<GDALWMSRasterBand *>(
103
                                band->GetOverview(m_overview));
75✔
104
                        if (!band->IsBlockInCache(ix, iy))
150✔
105
                            need_this_block = true;
150✔
106
                    }
107
                }
108
            }
109
            else
110
            {
111
                need_this_block = true;
×
112
            }
113

114
            void *p = ((ix == x) && (iy == y)) ? buffer : nullptr;
59✔
115
            if (need_this_block)
59✔
116
            {
117
                ret = AskMiniDriverForBlock(request, ix, iy);
59✔
118
                if (ret != CE_None)
59✔
119
                {
120
                    CPLError(CE_Failure, CPLE_AppDefined, "%s",
×
121
                             request.Error.c_str());
122
                    ret = CE_Failure;
×
123
                }
124
                // A missing tile is signaled by setting a range of "none"
125
                if (EQUAL(request.Range, "none"))
59✔
126
                {
127
                    if (!advise_read)
×
128
                    {
129
                        if (EmptyBlock(ix, iy, nBand, p) != CE_None)
×
130
                        {
131
                            CPLError(CE_Failure, CPLE_AppDefined,
×
132
                                     "GDALWMS: EmptyBlock failed.");
133
                            ret = CE_Failure;
×
134
                        }
135
                    }
136
                    need_this_block = false;
×
137
                }
138
                if (ret == CE_None && cache != nullptr)
59✔
139
                {
140
                    if (cache->GetItemStatus(request.URL) == CACHE_ITEM_OK)
36✔
141
                    {
142
                        if (advise_read)
12✔
143
                        {
144
                            need_this_block = false;
×
145
                        }
146
                        else
147
                        {
148
                            if (ReadBlockFromCache(request.URL, ix, iy, nBand,
12✔
149
                                                   p, 0) == CE_None)
12✔
150
                            {
151
                                need_this_block = false;
12✔
152
                            }
153
                        }
154
                    }
155
                }
156
            }
157

158
            if (need_this_block)
59✔
159
            {
160
                if (offline)
47✔
161
                {
162
                    if (!advise_read)
×
163
                    {
164
                        if (EmptyBlock(ix, iy, nBand, p) != CE_None)
×
165
                        {
166
                            CPLError(CE_Failure, CPLE_AppDefined,
×
167
                                     "GDALWMS: EmptyBlock failed.");
168
                            ret = CE_Failure;
×
169
                        }
170
                    }
171
                }
172
                else
173
                {
174
                    request.options = options;
47✔
175
                    WMSHTTPInitializeRequest(&request);
47✔
176
                    count++;
47✔
177
                }
178
            }
179
        }
180
    }
181

182
    // Fetch all the requests, OK to call with count of 0
183
    if (WMSHTTPFetchMulti(count ? &requests[0] : nullptr,
39✔
184
                          static_cast<int>(count)) != CE_None)
39✔
185
    {
186
        CPLError(CE_Failure, CPLE_AppDefined,
×
187
                 "GDALWMS: CPLHTTPFetchMulti failed.");
188
        ret = CE_Failure;
×
189
    }
190

191
    for (size_t i = 0; i < count; ++i)
86✔
192
    {
193
        WMSHTTPRequest &request = requests[i];
47✔
194
        void *p = ((request.x == x) && (request.y == y)) ? buffer : nullptr;
47✔
195
        if (ret == CE_None)
47✔
196
        {
197
            int success = (request.nStatus == 200) ||
53✔
198
                          (!request.Range.empty() && request.nStatus == 206);
6✔
199
            if (success && (request.pabyData != nullptr) &&
47✔
200
                (request.nDataLen > 0))
41✔
201
            {
202
                CPLString file_name(
203
                    BufferToVSIFile(request.pabyData, request.nDataLen));
82✔
204
                if (!file_name.empty())
41✔
205
                {
206
                    /* check for error xml */
207
                    if (request.nDataLen >= 20)
41✔
208
                    {
209
                        const char *download_data =
41✔
210
                            reinterpret_cast<char *>(request.pabyData);
211
                        if (STARTS_WITH_CI(download_data, "<?xml ") ||
41✔
212
                            STARTS_WITH_CI(download_data, "<!DOCTYPE ") ||
41✔
213
                            STARTS_WITH_CI(download_data, "<ServiceException"))
41✔
214
                        {
215
                            if (ReportWMSException(file_name) != CE_None)
×
216
                            {
217
                                CPLError(CE_Failure, CPLE_AppDefined,
×
218
                                         "GDALWMS: The server returned unknown "
219
                                         "exception.");
220
                            }
221
                            ret = CE_Failure;
×
222
                        }
223
                    }
224
                    if (ret == CE_None)
41✔
225
                    {
226
                        if (advise_read &&
41✔
227
                            !m_parent_dataset->m_verify_advise_read)
×
228
                        {
229
                            if (cache != nullptr)
×
230
                                cache->Insert(request.URL, file_name);
×
231
                        }
232
                        else
233
                        {
234
                            ret = ReadBlockFromFile(file_name, request.x,
41✔
235
                                                    request.y, nBand, p,
236
                                                    advise_read);
237
                            if (ret == CE_None)
41✔
238
                            {
239
                                if (cache != nullptr)
41✔
240
                                    cache->Insert(request.URL, file_name);
22✔
241
                            }
242
                            else
243
                            {
244
                                CPLError(
×
245
                                    ret, CPLE_AppDefined,
246
                                    "GDALWMS: ReadBlockFromFile (%s) failed.",
247
                                    request.URL.c_str());
248
                            }
249
                        }
250
                    }
251
                    else if (m_parent_dataset->m_zeroblock_on_serverexceptions)
×
252
                    {
253
                        ret = EmptyBlock(request.x, request.y, nBand, p);
×
254
                        if (ret != CE_None)
×
255
                            CPLError(ret, CPLE_AppDefined,
×
256
                                     "GDALWMS: EmptyBlock failed.");
257
                    }
258
                    VSIUnlink(file_name);
41✔
259
                }
41✔
260
            }
261
            else
262
            {  // HTTP error
263
                // One more try to get cached block. For example if no web
264
                // access available
265
                CPLDebug("WMS", "ReadBlockFromCache");
6✔
266

267
                if (m_parent_dataset->m_cache != nullptr)
6✔
268
                    ret = ReadBlockFromCache(request.URL, request.x, request.y,
2✔
269
                                             nBand, p, advise_read);
270
                else
271
                    ret = CE_Failure;
4✔
272

273
                if (ret != CE_None)
6✔
274
                {
275
                    CPLDebug("WMS", "After ReadBlockFromCache");
6✔
276
                    if (m_parent_dataset->m_http_zeroblock_codes.find(
12✔
277
                            request.nStatus) !=
6✔
278
                        m_parent_dataset->m_http_zeroblock_codes.end())
12✔
279
                    {
280
                        if (!advise_read)
2✔
281
                        {
282
                            ret = EmptyBlock(request.x, request.y, nBand, p);
2✔
283
                            if (ret != CE_None)
2✔
284
                                CPLError(ret, CPLE_AppDefined,
×
285
                                         "GDALWMS: EmptyBlock failed.");
286
                        }
287
                    }
288
                    else
289
                    {
290
                        ret = CE_Failure;
4✔
291
                        CPLError(ret, CPLE_AppDefined,
7✔
292
                                 "GDALWMS: Unable to download block %d, %d.\n"
293
                                 "URL: %s\n  HTTP status code: %d, error: %s.\n"
294
                                 "Add the HTTP status code to "
295
                                 "<ZeroBlockHttpCodes> to ignore this error "
296
                                 "(see https://gdal.org/frmt_wms.html).",
297
                                 request.x, request.y,
298
                                 !request.URL.empty() ? request.Error.c_str()
4✔
299
                                                      : "(null)",
300
                                 request.nStatus,
301
                                 !request.Error.empty() ? request.Error.c_str()
4✔
302
                                                        : "(null)");
303
                    }
304
                }
305
            }
306
        }
307
    }
308

309
    return ret;
78✔
310
}
311

312
CPLErr GDALWMSRasterBand::IReadBlock(int x, int y, void *buffer)
39✔
313
{
314
    int bx0 = x;
39✔
315
    int by0 = y;
39✔
316
    int bx1 = x;
39✔
317
    int by1 = y;
39✔
318

319
    bool bCancelHint = false;
39✔
320
    if ((m_parent_dataset->m_hint.m_valid) &&
39✔
321
        (m_parent_dataset->m_hint.m_overview == m_overview))
39✔
322
    {
323
        int tbx0 = m_parent_dataset->m_hint.m_x0 / nBlockXSize;
39✔
324
        int tby0 = m_parent_dataset->m_hint.m_y0 / nBlockYSize;
39✔
325
        int tbx1 = (m_parent_dataset->m_hint.m_x0 +
39✔
326
                    m_parent_dataset->m_hint.m_sx - 1) /
39✔
327
                   nBlockXSize;
39✔
328
        int tby1 = (m_parent_dataset->m_hint.m_y0 +
39✔
329
                    m_parent_dataset->m_hint.m_sy - 1) /
39✔
330
                   nBlockYSize;
39✔
331
        if ((tbx0 <= x) && (tby0 <= y) && (tbx1 >= x) && (tby1 >= y))
39✔
332
        {
333
            // Avoid downloading a insane number of tiles at once.
334
            // Limit to 30x30 tiles centered around block of interest.
335
            bx0 = std::max(x - 15, tbx0);
39✔
336
            by0 = std::max(y - 15, tby0);
39✔
337
            bx1 = std::min(x + 15, tbx1);
39✔
338
            by1 = std::min(y + 15, tby1);
39✔
339
            bCancelHint =
39✔
340
                (bx0 == tbx0 && by0 == tby0 && bx1 == tbx1 && by1 == tby1);
39✔
341
        }
342
    }
343

344
    CPLErr eErr = ReadBlocks(x, y, buffer, bx0, by0, bx1, by1, 0);
39✔
345

346
    if (bCancelHint)
39✔
347
    {
348
        m_parent_dataset->m_hint.m_valid = false;
39✔
349
    }
350

351
    return eErr;
39✔
352
}
353

354
CPLErr GDALWMSRasterBand::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx,
100✔
355
                                    int sy, void *buffer, int bsx, int bsy,
356
                                    GDALDataType bdt, GSpacing nPixelSpace,
357
                                    GSpacing nLineSpace,
358
                                    GDALRasterIOExtraArg *psExtraArg)
359
{
360
    CPLErr ret;
361

362
    if (rw != GF_Read)
100✔
363
        return CE_Failure;
×
364
    if (buffer == nullptr)
100✔
365
        return CE_Failure;
×
366
    if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0))
100✔
367
        return CE_None;
×
368

369
    m_parent_dataset->m_hint.m_x0 = x0;
100✔
370
    m_parent_dataset->m_hint.m_y0 = y0;
100✔
371
    m_parent_dataset->m_hint.m_sx = sx;
100✔
372
    m_parent_dataset->m_hint.m_sy = sy;
100✔
373
    m_parent_dataset->m_hint.m_overview = m_overview;
100✔
374
    m_parent_dataset->m_hint.m_valid = true;
100✔
375
    ret = GDALRasterBand::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt,
100✔
376
                                    nPixelSpace, nLineSpace, psExtraArg);
377
    m_parent_dataset->m_hint.m_valid = false;
100✔
378

379
    return ret;
100✔
380
}
381

382
int GDALWMSRasterBand::HasArbitraryOverviews()
×
383
{
384
    //    return m_parent_dataset->m_mini_driver_caps.m_has_arb_overviews;
385
    return 0;  // not implemented yet
×
386
}
387

388
int GDALWMSRasterBand::GetOverviewCount()
188✔
389
{
390
    return static_cast<int>(m_overviews.size());
188✔
391
}
392

393
GDALRasterBand *GDALWMSRasterBand::GetOverview(int n)
293✔
394
{
395
    if ((!m_overviews.empty()) && (static_cast<size_t>(n) < m_overviews.size()))
293✔
396
        return m_overviews[n];
293✔
397
    else
398
        return nullptr;
×
399
}
400

401
bool GDALWMSRasterBand::AddOverview(double scale)
5,623✔
402
{
403
    GDALWMSRasterBand *overview =
404
        new GDALWMSRasterBand(m_parent_dataset, nBand, scale);
5,623✔
405
    if (overview->GetXSize() == 0 || overview->GetYSize() == 0)
5,623✔
406
    {
407
        delete overview;
×
408
        return false;
×
409
    }
410
    std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin();
5,623✔
411
    for (; it != m_overviews.end(); ++it)
36,761✔
412
    {
413
        GDALWMSRasterBand *p = *it;
31,138✔
414
        if (p->m_scale < scale)
31,138✔
415
            break;
×
416
    }
417
    m_overviews.insert(it, overview);
5,623✔
418
    it = m_overviews.begin();
5,623✔
419
    for (int i = 0; it != m_overviews.end(); ++it, ++i)
42,384✔
420
    {
421
        GDALWMSRasterBand *p = *it;
36,761✔
422
        p->m_overview = i;
36,761✔
423
    }
424
    return true;
5,623✔
425
}
426

427
bool GDALWMSRasterBand::IsBlockInCache(int x, int y)
289✔
428
{
429
    bool ret = false;
289✔
430
    GDALRasterBlock *b = TryGetLockedBlockRef(x, y);
289✔
431
    if (b != nullptr)
289✔
432
    {
433
        ret = true;
×
434
        b->DropLock();
×
435
    }
436
    return ret;
289✔
437
}
438

439
// This is the function that calculates the block coordinates for the fetch
440
CPLErr GDALWMSRasterBand::AskMiniDriverForBlock(WMSHTTPRequest &r, int x, int y)
59✔
441
{
442
    GDALWMSImageRequestInfo iri;
59✔
443
    GDALWMSTiledImageRequestInfo tiri;
59✔
444

445
    ComputeRequestInfo(iri, tiri, x, y);
59✔
446
    return m_parent_dataset->m_mini_driver->TiledImageRequest(r, iri, tiri);
118✔
447
}
448

449
void GDALWMSRasterBand::ComputeRequestInfo(GDALWMSImageRequestInfo &iri,
59✔
450
                                           GDALWMSTiledImageRequestInfo &tiri,
451
                                           int x, int y)
452
{
453
    int x0 = std::max(0, x * nBlockXSize);
59✔
454
    int y0 = std::max(0, y * nBlockYSize);
59✔
455
    int x1 = std::max(0, (x + 1) * nBlockXSize);
59✔
456
    int y1 = std::max(0, (y + 1) * nBlockYSize);
59✔
457
    if (m_parent_dataset->m_clamp_requests)
59✔
458
    {
459
        x0 = std::min(x0, nRasterXSize);
59✔
460
        y0 = std::min(y0, nRasterYSize);
59✔
461
        x1 = std::min(x1, nRasterXSize);
59✔
462
        y1 = std::min(y1, nRasterYSize);
59✔
463
    }
464

465
    const double rx = (m_parent_dataset->m_data_window.m_x1 -
59✔
466
                       m_parent_dataset->m_data_window.m_x0) /
59✔
467
                      static_cast<double>(nRasterXSize);
59✔
468
    const double ry = (m_parent_dataset->m_data_window.m_y1 -
59✔
469
                       m_parent_dataset->m_data_window.m_y0) /
59✔
470
                      static_cast<double>(nRasterYSize);
59✔
471
    /* Use different method for x0,y0 and x1,y1 to make sure calculated values
472
     * are exact for corner requests */
473
    iri.m_x0 = x0 * rx + m_parent_dataset->m_data_window.m_x0;
59✔
474
    iri.m_y0 = y0 * ry + m_parent_dataset->m_data_window.m_y0;
59✔
475
    iri.m_x1 = m_parent_dataset->m_data_window.m_x1 - (nRasterXSize - x1) * rx;
59✔
476
    iri.m_y1 = m_parent_dataset->m_data_window.m_y1 - (nRasterYSize - y1) * ry;
59✔
477
    iri.m_sx = x1 - x0;
59✔
478
    iri.m_sy = y1 - y0;
59✔
479

480
    int level = m_overview + 1;
59✔
481
    tiri.m_x = (m_parent_dataset->m_data_window.m_tx >> level) + x;
59✔
482
    tiri.m_y = (m_parent_dataset->m_data_window.m_ty >> level) + y;
59✔
483
    tiri.m_level = m_parent_dataset->m_data_window.m_tlevel - level;
59✔
484
}
59✔
485

486
/************************************************************************/
487
/*                      GetMetadataDomainList()                         */
488
/************************************************************************/
489

490
char **GDALWMSRasterBand::GetMetadataDomainList()
×
491
{
492
    char **m_list = GDALPamRasterBand::GetMetadataDomainList();
×
493
    char **mini_list = m_parent_dataset->m_mini_driver->GetMetadataDomainList();
×
494
    if (mini_list != nullptr)
×
495
    {
496
        m_list = CSLMerge(m_list, mini_list);
×
497
        CSLDestroy(mini_list);
×
498
    }
499
    return m_list;
×
500
}
501

502
const char *GDALWMSRasterBand::GetMetadataItem(const char *pszName,
1,025✔
503
                                               const char *pszDomain)
504
{
505
    if (!m_parent_dataset->m_mini_driver_caps.m_has_getinfo ||
1,025✔
506
        !(pszDomain != nullptr && EQUAL(pszDomain, "LocationInfo") &&
20✔
507
          (STARTS_WITH_CI(pszName, "Pixel_") ||
×
508
           STARTS_WITH_CI(pszName, "GeoPixel_"))))
×
509
        return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
1,025✔
510

511
    /* ==================================================================== */
512
    /*      LocationInfo handling.                                          */
513
    /* ==================================================================== */
514

515
    /* -------------------------------------------------------------------- */
516
    /*      What pixel are we aiming at?                                    */
517
    /* -------------------------------------------------------------------- */
518
    int iPixel, iLine;
519
    if (STARTS_WITH_CI(pszName, "Pixel_"))
×
520
    {
521
        if (sscanf(pszName + 6, "%d_%d", &iPixel, &iLine) != 2)
×
522
            return nullptr;
×
523
    }
524
    else if (STARTS_WITH_CI(pszName, "GeoPixel_"))
×
525
    {
526
        GDALGeoTransform gt, invGT;
×
527
        double dfGeoX, dfGeoY;
528

529
        {
530
            dfGeoX = CPLAtof(pszName + 9);
×
531
            const char *pszUnderscore = strchr(pszName + 9, '_');
×
532
            if (!pszUnderscore)
×
533
                return nullptr;
×
534
            dfGeoY = CPLAtof(pszUnderscore + 1);
×
535
        }
536

537
        if (m_parent_dataset->GetGeoTransform(gt) != CE_None)
×
538
            return nullptr;
×
539

540
        if (!GDALInvGeoTransform(gt.data(), invGT.data()))
×
541
            return nullptr;
×
542

543
        iPixel = static_cast<int>(
×
544
            floor(invGT[0] + invGT[1] * dfGeoX + invGT[2] * dfGeoY));
×
545
        iLine = static_cast<int>(
×
546
            floor(invGT[3] + invGT[4] * dfGeoX + invGT[5] * dfGeoY));
×
547

548
        /* The GetDataset() for the WMS driver is always the main overview
549
         * level, so rescale */
550
        /* the values if we are an overview */
551
        if (m_overview >= 0)
×
552
        {
553
            iPixel = static_cast<int>(
×
554
                1.0 * iPixel * GetXSize() /
×
555
                m_parent_dataset->GetRasterBand(1)->GetXSize());
×
556
            iLine = static_cast<int>(
×
557
                1.0 * iLine * GetYSize() /
×
558
                m_parent_dataset->GetRasterBand(1)->GetYSize());
×
559
        }
560
    }
561
    else
562
        return nullptr;
×
563

564
    if (iPixel < 0 || iLine < 0 || iPixel >= GetXSize() || iLine >= GetYSize())
×
565
        return nullptr;
×
566

567
    if (nBand != 1)
×
568
    {
569
        GDALRasterBand *poFirstBand = m_parent_dataset->GetRasterBand(1);
×
570
        if (m_overview >= 0)
×
571
            poFirstBand = poFirstBand->GetOverview(m_overview);
×
572
        if (poFirstBand)
×
573
            return poFirstBand->GetMetadataItem(pszName, pszDomain);
×
574
    }
575

576
    GDALWMSImageRequestInfo iri;
×
577
    GDALWMSTiledImageRequestInfo tiri;
×
578
    int nBlockXOff = iPixel / nBlockXSize;
×
579
    int nBlockYOff = iLine / nBlockYSize;
×
580

581
    ComputeRequestInfo(iri, tiri, nBlockXOff, nBlockYOff);
×
582

583
    CPLString url;
×
584
    m_parent_dataset->m_mini_driver->GetTiledImageInfo(
×
585
        url, iri, tiri, iPixel % nBlockXSize, iLine % nBlockXSize);
×
586

587
    if (url.empty())
×
588
        return nullptr;
×
589

590
    CPLDebug("WMS", "URL = %s", url.c_str());
×
591

592
    if (url == osMetadataItemURL)
×
593
    {
594
        // osMetadataItem.c_str() MUST be used, and not osMetadataItem,
595
        // otherwise a temporary copy is returned
596
        return !osMetadataItem.empty() ? osMetadataItem.c_str() : nullptr;
×
597
    }
598

599
    osMetadataItemURL = url;
×
600

601
    // This is OK, CPLHTTPFetch does not touch the options
602
    char **papszOptions =
603
        const_cast<char **>(m_parent_dataset->GetHTTPRequestOpts());
×
604
    CPLHTTPResult *psResult = CPLHTTPFetch(url, papszOptions);
×
605

606
    CPLString pszRes;
×
607

608
    if (psResult && psResult->pabyData)
×
609
        pszRes = reinterpret_cast<const char *>(psResult->pabyData);
×
610
    CPLHTTPDestroyResult(psResult);
×
611

612
    if (pszRes.empty())
×
613
    {
614
        osMetadataItem = "";
×
615
        return nullptr;
×
616
    }
617

618
    osMetadataItem = "<LocationInfo>";
×
619
    CPLPushErrorHandler(CPLQuietErrorHandler);
×
620
    CPLXMLNode *psXML = CPLParseXMLString(pszRes);
×
621
    CPLPopErrorHandler();
×
622
    if (psXML != nullptr && psXML->eType == CXT_Element)
×
623
    {
624
        if (strcmp(psXML->pszValue, "?xml") == 0)
×
625
        {
626
            if (psXML->psNext)
×
627
            {
628
                char *pszXML = CPLSerializeXMLTree(psXML->psNext);
×
629
                osMetadataItem += pszXML;
×
630
                CPLFree(pszXML);
×
631
            }
632
        }
633
        else
634
        {
635
            osMetadataItem += pszRes;
×
636
        }
×
637
    }
638
    else
639
    {
640
        char *pszEscapedXML = CPLEscapeString(pszRes, -1, CPLES_XML_BUT_QUOTES);
×
641
        osMetadataItem += pszEscapedXML;
×
642
        CPLFree(pszEscapedXML);
×
643
    }
644
    if (psXML != nullptr)
×
645
        CPLDestroyXMLNode(psXML);
×
646

647
    osMetadataItem += "</LocationInfo>";
×
648

649
    // osMetadataItem.c_str() MUST be used, and not osMetadataItem,
650
    // otherwise a temporary copy is returned
651
    return osMetadataItem.c_str();
×
652
}
653

654
static const int *GetBandMapForExpand(int nSourceBands, int nWmsBands)
53✔
655
{
656
    static const int bandmap1to1[] = {1};
657
    static const int bandmap2to1[] = {1};
658
    static const int bandmap3to1[] = {1};
659
    static const int bandmap4to1[] = {1};
660

661
    static const int bandmap1to2[] = {1, 0};  // 0 == full opaque alpha band
662
    static const int bandmap2to2[] = {1, 2};
663
    static const int bandmap3to2[] = {1, 0};
664
    static const int bandmap4to2[] = {1, 4};
665

666
    static const int bandmap1to3[] = {1, 1, 1};
667
    static const int bandmap2to3[] = {1, 1, 1};
668
    static const int bandmap3to3[] = {1, 2, 3};
669
    static const int bandmap4to3[] = {1, 2, 3};
670

671
    static const int bandmap1to4[] = {1, 1, 1, 0};
672
    static const int bandmap2to4[] = {1, 1, 1, 2};
673
    static const int bandmap3to4[] = {1, 2, 3, 0};
674
    static const int bandmap4to4[] = {1, 2, 3, 4};
675

676
    static const int *const bandmap_selector[4][4] = {
677
        {bandmap1to1, bandmap2to1, bandmap3to1, bandmap4to1},
678
        {bandmap1to2, bandmap2to2, bandmap3to2, bandmap4to2},
679
        {bandmap1to3, bandmap2to3, bandmap3to3, bandmap4to3},
680
        {bandmap1to4, bandmap2to4, bandmap3to4, bandmap4to4},
681
    };
682

683
    if (nSourceBands > 4 || nSourceBands < 1)
53✔
684
    {
685
        return nullptr;
×
686
    }
687
    if (nWmsBands > 4 || nWmsBands < 1)
53✔
688
    {
689
        return nullptr;
×
690
    }
691
    return bandmap_selector[nWmsBands - 1][nSourceBands - 1];
53✔
692
}
693

694
CPLErr GDALWMSRasterBand::ReadBlockFromDataset(GDALDataset *ds, int x, int y,
53✔
695
                                               int to_buffer_band, void *buffer,
696
                                               int advise_read)
697
{
698
    CPLErr ret = CE_None;
53✔
699
    GByte *color_table = nullptr;
53✔
700
    int i;
701

702
    // CPLDebug("WMS", "ReadBlockFromDataset: to_buffer_band=%d, (x,y)=(%d,
703
    // %d)", to_buffer_band, x, y);
704

705
    /* expected size */
706
    const int esx = MIN(MAX(0, (x + 1) * nBlockXSize), nRasterXSize) -
53✔
707
                    MIN(MAX(0, x * nBlockXSize), nRasterXSize);
53✔
708
    const int esy = MIN(MAX(0, (y + 1) * nBlockYSize), nRasterYSize) -
53✔
709
                    MIN(MAX(0, y * nBlockYSize), nRasterYSize);
53✔
710

711
    int sx = ds->GetRasterXSize();
53✔
712
    int sy = ds->GetRasterYSize();
53✔
713
    /* Allow bigger than expected so pre-tiled constant size images work on
714
     * corners */
715
    if ((sx > nBlockXSize) || (sy > nBlockYSize) || (sx < esx) || (sy < esy))
53✔
716
    {
717
        CPLError(CE_Failure, CPLE_AppDefined,
×
718
                 "GDALWMS: Incorrect size %d x %d of downloaded block, "
719
                 "expected %d x %d, max %d x %d.",
720
                 sx, sy, esx, esy, nBlockXSize, nBlockYSize);
721
        ret = CE_Failure;
×
722
    }
723

724
    int nDSRasterCount = ds->GetRasterCount();
53✔
725
    if (ret == CE_None)
53✔
726
    {
727
        if (nDSRasterCount != m_parent_dataset->nBands)
53✔
728
        {
729
            /* Maybe its an image with color table */
730
            if ((eDataType == GDT_Byte) && (ds->GetRasterCount() == 1))
34✔
731
            {
732
                GDALRasterBand *rb = ds->GetRasterBand(1);
24✔
733
                if (rb->GetRasterDataType() == GDT_Byte)
24✔
734
                {
735
                    GDALColorTable *ct = rb->GetColorTable();
24✔
736
                    if (ct != nullptr)
24✔
737
                    {
738
                        if (!advise_read)
19✔
739
                        {
740
                            color_table = new GByte[256 * 4];
19✔
741
                            const int count =
742
                                MIN(256, ct->GetColorEntryCount());
19✔
743
                            for (i = 0; i < count; ++i)
796✔
744
                            {
745
                                GDALColorEntry ce;
746
                                ct->GetColorEntryAsRGB(i, &ce);
777✔
747
                                color_table[i] = static_cast<GByte>(ce.c1);
777✔
748
                                color_table[i + 256] =
777✔
749
                                    static_cast<GByte>(ce.c2);
777✔
750
                                color_table[i + 512] =
777✔
751
                                    static_cast<GByte>(ce.c3);
777✔
752
                                color_table[i + 768] =
777✔
753
                                    static_cast<GByte>(ce.c4);
777✔
754
                            }
755

756
                            for (i = count; i < 256; ++i)
4,106✔
757
                            {
758
                                color_table[i] = 0;
4,087✔
759
                                color_table[i + 256] = 0;
4,087✔
760
                                color_table[i + 512] = 0;
4,087✔
761
                                color_table[i + 768] = 0;
4,087✔
762
                            }
763
                        }
764
                    }
765
                    else if (m_parent_dataset->nBands <= 4)
5✔
766
                    {  // Promote single band to fake color table
767
                        color_table = new GByte[256 * 4];
5✔
768
                        for (i = 0; i < 256; i++)
1,285✔
769
                        {
770
                            color_table[i] = static_cast<GByte>(i);
1,280✔
771
                            color_table[i + 256] = static_cast<GByte>(i);
1,280✔
772
                            color_table[i + 512] = static_cast<GByte>(i);
1,280✔
773
                            color_table[i + 768] = 255;  // Transparency
1,280✔
774
                        }
775
                        if (m_parent_dataset->nBands == 2)
5✔
776
                        {  // Luma-Alpha fixup
777
                            for (i = 0; i < 256; i++)
×
778
                            {
779
                                color_table[i + 256] = 255;
×
780
                            }
781
                        }
782
                    }
783
                }
784
            }
785
        }
786
    }
787

788
    if (!advise_read)
53✔
789
    {
790
        const int *const bandmap =
791
            GetBandMapForExpand(nDSRasterCount, m_parent_dataset->nBands);
53✔
792
        for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
219✔
793
        {
794
            if (ret == CE_None)
166✔
795
            {
796
                void *p = nullptr;
166✔
797
                GDALRasterBlock *b = nullptr;
166✔
798
                if ((buffer != nullptr) && (ib == to_buffer_band))
166✔
799
                {
800
                    p = buffer;
33✔
801
                }
802
                else
803
                {
804
                    GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(
805
                        m_parent_dataset->GetRasterBand(ib));
133✔
806
                    if (m_overview >= 0)
133✔
807
                    {
808
                        band = static_cast<GDALWMSRasterBand *>(
809
                            band->GetOverview(m_overview));
73✔
810
                    }
811
                    if (!band->IsBlockInCache(x, y))
133✔
812
                    {
813
                        b = band->GetLockedBlockRef(x, y, true);
133✔
814
                        if (b != nullptr)
133✔
815
                        {
816
                            p = b->GetDataRef();
133✔
817
                            if (p == nullptr)
133✔
818
                            {
819
                                CPLError(CE_Failure, CPLE_AppDefined,
×
820
                                         "GDALWMS: GetDataRef returned NULL.");
821
                                ret = CE_Failure;
×
822
                            }
823
                        }
824
                    }
825
                    else
826
                    {
827
                        // CPLDebug("WMS", "Band %d, block (x,y)=(%d, %d)
828
                        // already in cache", band->GetBand(), x, y);
829
                    }
830
                }
831

832
                if (p != nullptr)
166✔
833
                {
834
                    int pixel_space = GDALGetDataTypeSizeBytes(eDataType);
166✔
835
                    int line_space = pixel_space * nBlockXSize;
166✔
836
                    if (color_table == nullptr)
166✔
837
                    {
838
                        if (bandmap == nullptr || bandmap[ib - 1] != 0)
88✔
839
                        {
840
                            GDALDataType dt = eDataType;
87✔
841
                            int nSourceBand = ib;
87✔
842
                            if (bandmap != nullptr)
87✔
843
                            {
844
                                nSourceBand = bandmap[ib - 1];
87✔
845
                            }
846
                            // Get the data from the PNG as stored instead of
847
                            // converting, if the server asks for that
848
                            // TODO: This hack is from #3493 - not sure it
849
                            // really belongs here.
850
                            if ((GDT_Int16 == dt) &&
87✔
851
                                (GDT_UInt16 ==
852
                                 ds->GetRasterBand(ib)->GetRasterDataType()))
×
853
                            {
854
                                dt = GDT_UInt16;
×
855
                            }
856

857
                            if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy,
87✔
858
                                             dt, 1, &nSourceBand, pixel_space,
859
                                             line_space, 0, nullptr) != CE_None)
87✔
860
                            {
861
                                CPLError(CE_Failure, CPLE_AppDefined,
×
862
                                         "GDALWMS: RasterIO failed on "
863
                                         "downloaded block.");
864
                                ret = CE_Failure;
×
865
                            }
87✔
866
                        }
867
                        else  // if( bandmap != nullptr && bandmap[ib - 1] == 0
868
                              // )
869
                        {  // parent expects 4 bands but file has fewer count so
870
                            // generate a all "opaque" 4th band
871
                            GByte *byte_buffer = reinterpret_cast<GByte *>(p);
1✔
872
                            for (int l_y = 0; l_y < sy; ++l_y)
129✔
873
                            {
874
                                for (int l_x = 0; l_x < sx; ++l_x)
16,512✔
875
                                {
876
                                    const int offset = l_x + l_y * line_space;
16,384✔
877
                                    byte_buffer[offset] =
16,384✔
878
                                        255;  // fill with opaque
879
                                }
880
                            }
881
                        }
882
                    }
883
                    else if (ib <= 4)
78✔
884
                    {
885
                        if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy,
78✔
886
                                         eDataType, 1, nullptr, pixel_space,
887
                                         line_space, 0, nullptr) != CE_None)
78✔
888
                        {
889
                            CPLError(CE_Failure, CPLE_AppDefined,
×
890
                                     "GDALWMS: RasterIO failed on downloaded "
891
                                     "block.");
892
                            ret = CE_Failure;
×
893
                        }
894

895
                        if (ret == CE_None)
78✔
896
                        {
897
                            GByte *band_color_table =
78✔
898
                                color_table + 256 * (ib - 1);
78✔
899
                            GByte *byte_buffer = reinterpret_cast<GByte *>(p);
78✔
900
                            for (int l_y = 0; l_y < sy; ++l_y)
20,558✔
901
                            {
902
                                for (int l_x = 0; l_x < sx; ++l_x)
5,918,720✔
903
                                {
904
                                    const int offset = l_x + l_y * line_space;
5,898,240✔
905
                                    byte_buffer[offset] =
5,898,240✔
906
                                        band_color_table[byte_buffer[offset]];
5,898,240✔
907
                                }
908
                            }
909
                        }
910
                    }
911
                    else
912
                    {
913
                        CPLError(CE_Failure, CPLE_AppDefined,
×
914
                                 "GDALWMS: Color table supports at most 4 "
915
                                 "components.");
916
                        ret = CE_Failure;
×
917
                    }
918
                }
919
                if (b != nullptr)
166✔
920
                {
921
                    b->DropLock();
133✔
922
                }
923
            }
924
        }
925
    }
926
    GDALClose(ds);
53✔
927

928
    if (color_table != nullptr)
53✔
929
    {
930
        delete[] color_table;
24✔
931
    }
932

933
    return ret;
53✔
934
}
935

936
CPLErr GDALWMSRasterBand::ReadBlockFromFile(const CPLString &soFileName, int x,
41✔
937
                                            int y, int to_buffer_band,
938
                                            void *buffer, int advise_read)
939
{
940
    GDALDataset *ds = GDALDataset::FromHandle(GDALOpenEx(
41✔
941
        soFileName, GDAL_OF_RASTER | GDAL_OF_READONLY | GDAL_OF_VERBOSE_ERROR,
942
        nullptr, m_parent_dataset->m_tileOO, nullptr));
41✔
943
    if (ds == nullptr)
41✔
944
    {
945
        CPLError(CE_Failure, CPLE_AppDefined,
×
946
                 "GDALWMS: Unable to open downloaded block.");
947
        return CE_Failure;
×
948
    }
949

950
    return ReadBlockFromDataset(ds, x, y, to_buffer_band, buffer, advise_read);
41✔
951
}
952

953
CPLErr GDALWMSRasterBand::ReadBlockFromCache(const char *pszKey, int x, int y,
14✔
954
                                             int to_buffer_band, void *buffer,
955
                                             int advise_read)
956
{
957
    GDALWMSCache *cache = m_parent_dataset->m_cache;
14✔
958
    if (nullptr == cache)
14✔
959
    {
960
        CPLError(CE_Failure, CPLE_AppDefined,
×
961
                 "GDALWMS: Unable to open downloaded block.");
962
        return CE_Failure;
×
963
    }
964
    GDALDataset *ds = cache->GetDataset(pszKey, m_parent_dataset->m_tileOO);
14✔
965
    if (ds == nullptr)
14✔
966
    {
967
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
968
                 "GDALWMS: Unable to open downloaded block.");
969
        return CE_Failure;
2✔
970
    }
971

972
    return ReadBlockFromDataset(ds, x, y, to_buffer_band, buffer, advise_read);
12✔
973
}
974

975
CPLErr GDALWMSRasterBand::EmptyBlock(int x, int y, int to_buffer_band,
2✔
976
                                     void *buffer)
977
{
978
    CPLErr ret = CE_None;
2✔
979

980
    for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
10✔
981
    {
982
        if (ret == CE_None)
8✔
983
        {
984
            void *p = nullptr;
8✔
985
            GDALRasterBlock *b = nullptr;
8✔
986
            GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(
987
                m_parent_dataset->GetRasterBand(ib));
8✔
988
            if (m_overview >= 0)
8✔
989
                band = static_cast<GDALWMSRasterBand *>(
990
                    band->GetOverview(m_overview));
×
991
            if ((buffer != nullptr) && (ib == to_buffer_band))
8✔
992
            {
993
                p = buffer;
2✔
994
            }
995
            else
996
            {
997
                if (!band->IsBlockInCache(x, y))
6✔
998
                {
999
                    b = band->GetLockedBlockRef(x, y, true);
6✔
1000
                    if (b != nullptr)
6✔
1001
                    {
1002
                        p = b->GetDataRef();
6✔
1003
                        if (p == nullptr)
6✔
1004
                        {
1005
                            CPLError(CE_Failure, CPLE_AppDefined,
×
1006
                                     "GDALWMS: GetDataRef returned NULL.");
1007
                            ret = CE_Failure;
×
1008
                        }
1009
                    }
1010
                }
1011
            }
1012
            if (p != nullptr)
8✔
1013
            {
1014
                int hasNDV;
1015
                double valNDV = band->GetNoDataValue(&hasNDV);
8✔
1016
                if (!hasNDV)
8✔
1017
                    valNDV = 0;
8✔
1018
                GDALCopyWords(&valNDV, GDT_Float64, 0, p, eDataType,
8✔
1019
                              GDALGetDataTypeSizeBytes(eDataType),
1020
                              nBlockXSize * nBlockYSize);
8✔
1021
            }
1022
            if (b != nullptr)
8✔
1023
            {
1024
                b->DropLock();
6✔
1025
            }
1026
        }
1027
    }
1028

1029
    return ret;
2✔
1030
}
1031

1032
CPLErr GDALWMSRasterBand::ReportWMSException(const char *file_name)
×
1033
{
1034
    CPLErr ret = CE_None;
×
1035
    int reported_errors_count = 0;
×
1036

1037
    CPLXMLNode *orig_root = CPLParseXMLFile(file_name);
×
1038
    CPLXMLNode *root = orig_root;
×
1039
    if (root != nullptr)
×
1040
    {
1041
        root = CPLGetXMLNode(root, "=ServiceExceptionReport");
×
1042
    }
1043
    if (root != nullptr)
×
1044
    {
1045
        CPLXMLNode *n = CPLGetXMLNode(root, "ServiceException");
×
1046
        while (n != nullptr)
×
1047
        {
1048
            const char *exception = CPLGetXMLValue(n, "=ServiceException", "");
×
1049
            const char *exception_code =
1050
                CPLGetXMLValue(n, "=ServiceException.code", "");
×
1051
            if (exception[0] != '\0')
×
1052
            {
1053
                if (exception_code[0] != '\0')
×
1054
                {
1055
                    CPLError(
×
1056
                        CE_Failure, CPLE_AppDefined,
1057
                        "GDALWMS: The server returned exception code '%s': %s",
1058
                        exception_code, exception);
1059
                    ++reported_errors_count;
×
1060
                }
1061
                else
1062
                {
1063
                    CPLError(CE_Failure, CPLE_AppDefined,
×
1064
                             "GDALWMS: The server returned exception: %s",
1065
                             exception);
1066
                    ++reported_errors_count;
×
1067
                }
1068
            }
1069
            else if (exception_code[0] != '\0')
×
1070
            {
1071
                CPLError(CE_Failure, CPLE_AppDefined,
×
1072
                         "GDALWMS: The server returned exception code '%s'.",
1073
                         exception_code);
1074
                ++reported_errors_count;
×
1075
            }
1076

1077
            n = n->psNext;
×
1078
            if (n != nullptr)
×
1079
            {
1080
                n = CPLGetXMLNode(n, "=ServiceException");
×
1081
            }
1082
        }
1083
    }
1084
    else
1085
    {
1086
        ret = CE_Failure;
×
1087
    }
1088
    if (orig_root != nullptr)
×
1089
    {
1090
        CPLDestroyXMLNode(orig_root);
×
1091
    }
1092

1093
    if (reported_errors_count == 0)
×
1094
    {
1095
        ret = CE_Failure;
×
1096
    }
1097

1098
    return ret;
×
1099
}
1100

1101
CPLErr GDALWMSRasterBand::AdviseRead(int nXOff, int nYOff, int nXSize,
×
1102
                                     int nYSize, int nBufXSize, int nBufYSize,
1103
                                     GDALDataType eDT, char **papszOptions)
1104
{
1105
    //    printf("AdviseRead(%d, %d, %d, %d)\n", nXOff, nYOff, nXSize, nYSize);
1106
    if (m_parent_dataset->m_offline_mode ||
×
1107
        !m_parent_dataset->m_use_advise_read)
×
1108
        return CE_None;
×
1109
    if (m_parent_dataset->m_cache == nullptr)
×
1110
        return CE_Failure;
×
1111

1112
    /* ==================================================================== */
1113
    /*      Do we have overviews that would be appropriate to satisfy       */
1114
    /*      this request?                                                   */
1115
    /* ==================================================================== */
1116
    if ((nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0)
×
1117
    {
1118
        const int nOverview = GDALBandGetBestOverviewLevel2(
×
1119
            this, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, nullptr);
1120
        if (nOverview >= 0)
×
1121
        {
1122
            GDALRasterBand *poOverviewBand = GetOverview(nOverview);
×
1123
            if (poOverviewBand == nullptr)
×
1124
                return CE_Failure;
×
1125

1126
            return poOverviewBand->AdviseRead(nXOff, nYOff, nXSize, nYSize,
×
1127
                                              nBufXSize, nBufYSize, eDT,
1128
                                              papszOptions);
×
1129
        }
1130
    }
1131

1132
    int bx0 = nXOff / nBlockXSize;
×
1133
    int by0 = nYOff / nBlockYSize;
×
1134
    int bx1 = (nXOff + nXSize - 1) / nBlockXSize;
×
1135
    int by1 = (nYOff + nYSize - 1) / nBlockYSize;
×
1136

1137
    // Avoid downloading a insane number of tiles
1138
    const int MAX_TILES = 1000;  // arbitrary number
×
1139
    if ((bx1 - bx0 + 1) > MAX_TILES / (by1 - by0 + 1))
×
1140
    {
1141
        CPLDebug("WMS", "Too many tiles for AdviseRead()");
×
1142
        return CE_Failure;
×
1143
    }
1144

1145
    if (m_nAdviseReadBX0 == bx0 && m_nAdviseReadBY0 == by0 &&
×
1146
        m_nAdviseReadBX1 == bx1 && m_nAdviseReadBY1 == by1)
×
1147
    {
1148
        return CE_None;
×
1149
    }
1150
    m_nAdviseReadBX0 = bx0;
×
1151
    m_nAdviseReadBY0 = by0;
×
1152
    m_nAdviseReadBX1 = bx1;
×
1153
    m_nAdviseReadBY1 = by1;
×
1154

1155
    return ReadBlocks(0, 0, nullptr, bx0, by0, bx1, by1, 1);
×
1156
}
1157

1158
GDALColorInterp GDALWMSRasterBand::GetColorInterpretation()
415✔
1159
{
1160
    return m_color_interp;
415✔
1161
}
1162

1163
CPLErr GDALWMSRasterBand::SetColorInterpretation(GDALColorInterp eNewInterp)
9✔
1164
{
1165
    m_color_interp = eNewInterp;
9✔
1166
    return CE_None;
9✔
1167
}
1168

1169
// Utility function, returns a value from a vector corresponding to the band
1170
// index or the first entry
1171
static double getBandValue(const std::vector<double> &v, size_t idx)
×
1172
{
1173
    idx--;
×
1174
    if (v.size() > idx)
×
1175
        return v[idx];
×
1176
    return v[0];
×
1177
}
1178

1179
double GDALWMSRasterBand::GetNoDataValue(int *pbSuccess)
493✔
1180
{
1181
    std::vector<double> &v = m_parent_dataset->vNoData;
493✔
1182
    if (v.empty())
493✔
1183
        return GDALPamRasterBand::GetNoDataValue(pbSuccess);
493✔
1184
    if (pbSuccess)
×
1185
        *pbSuccess = TRUE;
×
1186
    return getBandValue(v, nBand);
×
1187
}
1188

1189
double GDALWMSRasterBand::GetMinimum(int *pbSuccess)
×
1190
{
1191
    std::vector<double> &v = m_parent_dataset->vMin;
×
1192
    if (v.empty())
×
1193
        return GDALPamRasterBand::GetMinimum(pbSuccess);
×
1194
    if (pbSuccess)
×
1195
        *pbSuccess = TRUE;
×
1196
    return getBandValue(v, nBand);
×
1197
}
1198

1199
double GDALWMSRasterBand::GetMaximum(int *pbSuccess)
×
1200
{
1201
    std::vector<double> &v = m_parent_dataset->vMax;
×
1202
    if (v.empty())
×
1203
        return GDALPamRasterBand::GetMaximum(pbSuccess);
×
1204
    if (pbSuccess)
×
1205
        *pbSuccess = TRUE;
×
1206
    return getBandValue(v, nBand);
×
1207
}
1208

1209
GDALColorTable *GDALWMSRasterBand::GetColorTable()
316✔
1210
{
1211
    return m_parent_dataset->m_poColorTable;
316✔
1212
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc