Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/wms/wmsdriver.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  WMS Client Driver
4
 * Purpose:  Implementation of Dataset and RasterBand classes for WMS
5
 *           and other similar services.
6
 * Author:   Adam Nowacki, nowak@xpam.de
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2007, Adam Nowacki
10
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
11
 * Copyright (c) 2017, Dmitry Baryshnikov, <polimax@mail.ru>
12
 * Copyright (c) 2017, NextGIS, <info@nextgis.com>
13
 *
14
 * SPDX-License-Identifier: MIT
15
 ****************************************************************************/
16
17
#ifndef WMSDRIVER_H_INCLUDED
18
#define WMSDRIVER_H_INCLUDED
19
20
#include <algorithm>
21
#include <cmath>
22
#include <map>
23
#include <set>
24
#include <vector>
25
#include <utility>
26
27
#include "cpl_conv.h"
28
#include "cpl_curl_priv.h"
29
#include "cpl_http.h"
30
#include "gdal_alg.h"
31
#include "gdal_pam.h"
32
#include "gdalwarper.h"
33
#include "ogr_spatialref.h"
34
35
#include "gdalhttp.h"
36
37
class GDALWMSDataset;
38
class GDALWMSRasterBand;
39
40
/* -------------------------------------------------------------------- */
41
/*      Helper functions.                                               */
42
/* -------------------------------------------------------------------- */
43
OGRSpatialReference ProjToSRS(const CPLString &proj);
44
45
// Decode s from encoding "base64" or "XMLencoded".
46
// If encoding is "file", s is the file name on input and file content on output
47
// If encoding is not recognized, does nothing
48
const char *WMSUtilDecode(CPLString &s, const char *encoding);
49
50
// Ensure that the url ends in ? or &
51
void URLPrepare(CPLString &url);
52
// void URLAppend(CPLString *url, const char *s);
53
// void URLAppendF(CPLString *url, const char *s, ...) CPL_PRINT_FUNC_FORMAT (2,
54
// 3); void URLAppend(CPLString *url, const CPLString &s);
55
CPLString BufferToVSIFile(GByte *buffer, size_t size);
56
57
int StrToBool(const char *p);
58
int URLSearchAndReplace(CPLString *base, const char *search, const char *fmt,
59
                        ...) CPL_PRINT_FUNC_FORMAT(3, 4);
60
/* Convert a.b.c.d to a * 0x1000000 + b * 0x10000 + c * 0x100 + d */
61
int VersionStringToInt(const char *version);
62
63
class GDALWMSImageRequestInfo
64
{
65
  public:
66
    double m_x0{}, m_y0{};
67
    double m_x1{}, m_y1{};
68
    int m_sx{}, m_sy{};
69
};
70
71
class GDALWMSDataWindow
72
{
73
  public:
74
    double m_x0, m_y0;
75
    double m_x1, m_y1;
76
    int m_sx, m_sy;
77
    int m_tx, m_ty, m_tlevel;
78
79
    enum
80
    {
81
        BOTTOM = -1,
82
        DEFAULT = 0,
83
        TOP = 1
84
    } m_y_origin;
85
86
    GDALWMSDataWindow()
87
26.2k
        : m_x0(-180), m_y0(90), m_x1(180), m_y1(-90), m_sx(-1), m_sy(-1),
88
26.2k
          m_tx(0), m_ty(0), m_tlevel(-1), m_y_origin(DEFAULT)
89
26.2k
    {
90
26.2k
    }
91
};
92
93
class GDALWMSTiledImageRequestInfo
94
{
95
  public:
96
    int m_x{}, m_y{};
97
    int m_level{};
98
};
99
100
/************************************************************************/
101
/*                         Mini Driver Related                          */
102
/************************************************************************/
103
104
class GDALWMSRasterIOHint
105
{
106
  public:
107
    GDALWMSRasterIOHint()
108
13.1k
        : m_x0(0), m_y0(0), m_sx(0), m_sy(0), m_overview(0), m_valid(false)
109
13.1k
    {
110
13.1k
    }
111
112
    int m_x0;
113
    int m_y0;
114
    int m_sx;
115
    int m_sy;
116
    int m_overview;
117
    bool m_valid;
118
};
119
120
typedef enum
121
{
122
    OVERVIEW_ROUNDED,
123
    OVERVIEW_FLOOR
124
} GDALWMSOverviewDimComputationMethod;
125
126
class WMSMiniDriverCapabilities
127
{
128
  public:
129
    // Default capabilities, suitable in most cases
130
    WMSMiniDriverCapabilities() = default;
131
132
    int m_has_getinfo{0};  // Does it have meaningful implementation
133
    int m_has_geotransform{1};
134
    GDALWMSOverviewDimComputationMethod m_overview_dim_computation_method{
135
        OVERVIEW_ROUNDED};
136
};
137
138
/* All data returned by mini-driver as pointer should remain valid for
139
   mini-driver lifetime and should be freed by mini-driver destructor unless
140
   otherwise specified.
141
 */
142
143
// Base class for minidrivers
144
// A minidriver has to implement at least the Initialize and the
145
// TiledImageRequest
146
//
147
class WMSMiniDriver /* non final */
148
{
149
    friend class GDALWMSDataset;
150
151
    CPL_DISALLOW_COPY_ASSIGN(WMSMiniDriver)
152
153
  public:
154
13.1k
    WMSMiniDriver() : m_parent_dataset(nullptr)
155
13.1k
    {
156
13.1k
        m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
157
13.1k
    }
158
159
    virtual ~WMSMiniDriver();
160
161
  public:
162
    // MiniDriver specific initialization from XML, required
163
    // Called once at the beginning of the dataset initialization
164
    virtual CPLErr Initialize(CPLXMLNode *config, char **papszOpenOptions) = 0;
165
166
    // Called once at the end of the dataset initialization
167
    virtual CPLErr EndInit()
168
13.1k
    {
169
13.1k
        return CE_None;
170
13.1k
    }
171
172
    // Error message returned in url, required
173
    // Set error message in request.Error
174
    // If tile doesn't exist serverside, set request.range to "none"
175
    virtual CPLErr
176
    TiledImageRequest(CPL_UNUSED WMSHTTPRequest &,
177
                      CPL_UNUSED const GDALWMSImageRequestInfo &iri,
178
                      CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri) = 0;
179
180
    // change capabilities to be used by the parent
181
    virtual void GetCapabilities(CPL_UNUSED WMSMiniDriverCapabilities *caps)
182
259
    {
183
259
    }
184
185
    // signal by setting the m_has_getinfo in the GetCapabilities call
186
    virtual void
187
    GetTiledImageInfo(CPL_UNUSED CPLString &url,
188
                      CPL_UNUSED const GDALWMSImageRequestInfo &iri,
189
                      CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri,
190
                      CPL_UNUSED int nXInBlock, CPL_UNUSED int nYInBlock)
191
0
    {
192
0
    }
193
194
    virtual const OGRSpatialReference &GetSpatialRef() const
195
13.1k
    {
196
13.1k
        return m_oSRS;
197
13.1k
    }
198
199
    virtual char **GetMetadataDomainList()
200
0
    {
201
0
        return nullptr;
202
0
    }
203
204
  protected:
205
    CPLString m_base_url{};
206
    OGRSpatialReference m_oSRS{};
207
    GDALWMSDataset *m_parent_dataset{};
208
};
209
210
class WMSMiniDriverFactory /* non final */
211
{
212
  public:
213
    virtual ~WMSMiniDriverFactory();
214
    virtual WMSMiniDriver *New() const = 0;
215
    CPLString m_name{};
216
217
  protected:
218
264
    WMSMiniDriverFactory() = default;
219
};
220
221
// Interface with the global mini driver manager
222
WMSMiniDriver *NewWMSMiniDriver(const CPLString &name);
223
void WMSRegisterMiniDriverFactory(WMSMiniDriverFactory *mdf);
224
void WMSDeregisterMiniDrivers(GDALDriver *);
225
226
// WARNING: Called by GDALDestructor, unsafe to use any static objects
227
void WMSDeregister(GDALDriver *);
228
229
/************************************************************************/
230
/*                             GDALWMSCache                             */
231
/************************************************************************/
232
enum GDALWMSCacheItemStatus
233
{
234
    CACHE_ITEM_NOT_FOUND,
235
    CACHE_ITEM_OK,
236
    CACHE_ITEM_EXPIRED
237
};
238
239
class GDALWMSCacheImpl /* non final */
240
{
241
  public:
242
    GDALWMSCacheImpl(const CPLString &soPath, CPLXMLNode * /*pConfig*/)
243
259
        : m_soPath(soPath)
244
259
    {
245
259
    }
246
247
    virtual ~GDALWMSCacheImpl();
248
249
    virtual CPLErr Insert(const char *pszKey, const CPLString &osFileName) = 0;
250
    virtual enum GDALWMSCacheItemStatus
251
    GetItemStatus(const char *pszKey) const = 0;
252
    virtual GDALDataset *GetDataset(const char *pszKey,
253
                                    char **papszOpenOptions) const = 0;
254
    virtual void Clean() = 0;
255
    virtual int GetCleanThreadRunTimeout() = 0;
256
257
  protected:
258
    CPLString m_soPath;
259
};
260
261
class GDALWMSCache final
262
{
263
    friend class GDALWMSDataset;
264
265
  public:
266
    GDALWMSCache();
267
    ~GDALWMSCache();
268
269
  public:
270
    CPLErr Initialize(const char *pszUrl, CPLXMLNode *pConfig);
271
    CPLErr Insert(const char *pszKey, const CPLString &osFileName);
272
    enum GDALWMSCacheItemStatus GetItemStatus(const char *pszKey) const;
273
    GDALDataset *GetDataset(const char *pszKey, char **papszOpenOptions) const;
274
    void Clean();
275
276
  protected:
277
    CPLString CachePath() const
278
259
    {
279
259
        return m_osCachePath;
280
259
    }
281
282
  protected:
283
    CPLString m_osCachePath{};
284
    bool m_bIsCleanThreadRunning = false;
285
    time_t m_nCleanThreadLastRunTime = 0;
286
287
  private:
288
    GDALWMSCacheImpl *m_poCache = nullptr;
289
    CPLJoinableThread *m_hThread = nullptr;
290
291
    CPL_DISALLOW_COPY_ASSIGN(GDALWMSCache)
292
};
293
294
/************************************************************************/
295
/*                            GDALWMSDataset                            */
296
/************************************************************************/
297
298
class GDALWMSDataset final : public GDALPamDataset
299
{
300
    friend class GDALWMSRasterBand;
301
302
    CPL_DISALLOW_COPY_ASSIGN(GDALWMSDataset)
303
304
  public:
305
    GDALWMSDataset();
306
    ~GDALWMSDataset() override;
307
308
    const OGRSpatialReference *GetSpatialRef() const override;
309
    CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
310
311
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
312
    CPLErr SetGeoTransform(const GDALGeoTransform &gt) override;
313
    CPLErr AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy,
314
                      GDALDataType bdt, int band_count, int *band_map,
315
                      CSLConstList options) override;
316
317
    char **GetMetadataDomainList() override;
318
    virtual const char *GetMetadataItem(const char *pszName,
319
                                        const char *pszDomain = "") override;
320
321
    void SetColorTable(GDALColorTable *pct)
322
0
    {
323
0
        m_poColorTable = pct;
324
0
    }
325
326
    void mSetBand(int i, GDALRasterBand *band)
327
0
    {
328
0
        SetBand(i, band);
329
0
    }
330
331
    GDALWMSRasterBand *mGetBand(int i)
332
0
    {
333
0
        return reinterpret_cast<GDALWMSRasterBand *>(GetRasterBand(i));
334
0
    }
335
336
    const GDALWMSDataWindow *WMSGetDataWindow() const
337
544
    {
338
544
        return &m_data_window;
339
544
    }
340
341
    void WMSSetBlockSize(int x, int y)
342
0
    {
343
0
        m_block_size_x = x;
344
0
        m_block_size_y = y;
345
0
    }
346
347
    void WMSSetRasterSize(int x, int y)
348
0
    {
349
0
        nRasterXSize = x;
350
0
        nRasterYSize = y;
351
0
    }
352
353
    void WMSSetBandsCount(int count)
354
0
    {
355
0
        nBands = count;
356
0
    }
357
358
    void WMSSetClamp(bool flag = true)
359
0
    {
360
0
        m_clamp_requests = flag;
361
0
    }
362
363
    void WMSSetDataType(GDALDataType type)
364
0
    {
365
0
        m_data_type = type;
366
0
    }
367
368
    void WMSSetDataWindow(const GDALWMSDataWindow &window)
369
0
    {
370
0
        m_data_window = window;
371
0
    }
372
373
    void WMSSetDefaultBlockSize(int x, int y)
374
0
    {
375
0
        m_default_block_size_x = x;
376
0
        m_default_block_size_y = y;
377
0
    }
378
379
    void WMSSetDefaultDataWindowCoordinates(double x0, double y0, double x1,
380
                                            double y1)
381
0
    {
382
0
        m_default_data_window.m_x0 = x0;
383
0
        m_default_data_window.m_y0 = y0;
384
0
        m_default_data_window.m_x1 = x1;
385
0
        m_default_data_window.m_y1 = y1;
386
0
    }
387
388
    void WMSSetDefaultTileCount(int tilecountx, int tilecounty)
389
0
    {
390
0
        m_default_tile_count_x = tilecountx;
391
0
        m_default_tile_count_y = tilecounty;
392
0
    }
393
394
    void WMSSetDefaultTileLevel(int tlevel)
395
0
    {
396
0
        m_default_data_window.m_tlevel = tlevel;
397
0
    }
398
399
    void WMSSetDefaultOverviewCount(int overview_count)
400
0
    {
401
0
        m_default_overview_count = overview_count;
402
0
    }
403
404
    void WMSSetNeedsDataWindow(bool flag)
405
0
    {
406
0
        m_bNeedsDataWindow = flag;
407
0
    }
408
409
    static void list2vec(std::vector<double> &v, const char *pszList)
410
0
    {
411
0
        if ((pszList == nullptr) || (pszList[0] == 0))
412
0
            return;
413
0
        char **papszTokens = CSLTokenizeString2(
414
0
            pszList, " \t\n\r", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
415
0
        v.clear();
416
0
        for (int i = 0; i < CSLCount(papszTokens); i++)
417
0
            v.push_back(CPLStrtod(papszTokens[i], nullptr));
418
0
        CSLDestroy(papszTokens);
419
0
    }
420
421
    void WMSSetNoDataValue(const char *pszNoData)
422
0
    {
423
0
        list2vec(vNoData, pszNoData);
424
0
    }
425
426
    void WMSSetMinValue(const char *pszMin)
427
0
    {
428
0
        list2vec(vMin, pszMin);
429
0
    }
430
431
    void WMSSetMaxValue(const char *pszMax)
432
0
    {
433
0
        list2vec(vMax, pszMax);
434
0
    }
435
436
    // Set open options for tiles
437
    // Works like a <set>, only one entry with a give name can exist, last one
438
    // set wins If the value is null, the entry is deleted
439
    void SetTileOO(const char *pszName, const char *pszValue);
440
441
    void SetXML(const char *psz)
442
0
    {
443
0
        m_osXML.clear();
444
0
        if (psz)
445
0
            m_osXML = psz;
446
0
    }
447
448
    static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
449
    static GDALDataset *CreateCopy(const char *pszFilename,
450
                                   GDALDataset *poSrcDS, int bStrict,
451
                                   CSLConstList papszOptions,
452
                                   GDALProgressFunc pfnProgress,
453
                                   void *pProgressData);
454
455
    const char *const *GetHTTPRequestOpts();
456
457
    static const char *GetServerConfig(const char *URI,
458
                                       char **papszHTTPOptions);
459
    static void DestroyCfgMutex();
460
    static void ClearConfigCache();
461
462
  protected:
463
    CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
464
                     void *buffer, int bsx, int bsy, GDALDataType bdt,
465
                     int band_count, BANDMAP_TYPE band_map,
466
                     GSpacing nPixelSpace, GSpacing nLineSpace,
467
                     GSpacing nBandSpace,
468
                     GDALRasterIOExtraArg *psExtraArg) override;
469
    CPLErr Initialize(CPLXMLNode *config, char **papszOpenOptions);
470
471
    GDALWMSDataWindow m_data_window{};
472
    WMSMiniDriver *m_mini_driver{};
473
    WMSMiniDriverCapabilities m_mini_driver_caps{};
474
    GDALWMSCache *m_cache{};
475
    OGRSpatialReference m_oSRS{};
476
    GDALColorTable *m_poColorTable{};
477
    std::vector<double> vNoData{};
478
    std::vector<double> vMin{};
479
    std::vector<double> vMax{};
480
    GDALDataType m_data_type{GDT_Unknown};
481
    int m_block_size_x{};
482
    int m_block_size_y{};
483
    GDALWMSRasterIOHint m_hint{};
484
    int m_use_advise_read{};
485
    int m_verify_advise_read{};
486
    int m_offline_mode{};
487
    int m_http_max_conn{};
488
    int m_http_timeout{};
489
    char **m_http_options{};
490
    // Open Option list for tiles
491
    char **m_tileOO{};
492
    int m_clamp_requests{};
493
    int m_unsafeSsl{};
494
    std::set<int> m_http_zeroblock_codes{};
495
    int m_zeroblock_on_serverexceptions{};
496
    CPLString m_osUserAgent{};
497
    CPLString m_osReferer{};
498
    CPLString m_osUserPwd{};
499
    std::string m_osAccept{};  // HTTP Accept header
500
501
    GDALWMSDataWindow m_default_data_window{};
502
    int m_default_block_size_x{};
503
    int m_default_block_size_y{};
504
    int m_default_tile_count_x{};
505
    int m_default_tile_count_y{};
506
    int m_default_overview_count{};
507
508
    bool m_bNeedsDataWindow{};
509
510
    CPLString m_osXML{};
511
512
    // Per session cache of server configurations
513
    typedef std::map<CPLString, CPLString> StringMap_t;
514
    static CPLMutex *cfgmtx;
515
    static StringMap_t cfg;
516
};
517
518
/************************************************************************/
519
/*                          GDALWMSRasterBand                           */
520
/************************************************************************/
521
522
class GDALWMSRasterBand final : public GDALPamRasterBand
523
{
524
    friend class GDALWMSDataset;
525
    void ComputeRequestInfo(GDALWMSImageRequestInfo &iri,
526
                            GDALWMSTiledImageRequestInfo &tiri, int x, int y);
527
528
    CPLString osMetadataItem{};
529
    CPLString osMetadataItemURL{};
530
531
    CPL_DISALLOW_COPY_ASSIGN(GDALWMSRasterBand)
532
533
  public:
534
    GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band, double scale);
535
    ~GDALWMSRasterBand() override;
536
    bool AddOverview(double scale);
537
    double GetNoDataValue(int *) override;
538
    double GetMinimum(int *) override;
539
    double GetMaximum(int *) override;
540
    GDALColorTable *GetColorTable() override;
541
    CPLErr AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy,
542
                      GDALDataType bdt, CSLConstList options) override;
543
544
    GDALColorInterp GetColorInterpretation() override;
545
    CPLErr SetColorInterpretation(GDALColorInterp) override;
546
    CPLErr IReadBlock(int x, int y, void *buffer) override;
547
    CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
548
                     void *buffer, int bsx, int bsy, GDALDataType bdt,
549
                     GSpacing nPixelSpace, GSpacing nLineSpace,
550
                     GDALRasterIOExtraArg *psExtraArg) override;
551
    int HasArbitraryOverviews() override;
552
    int GetOverviewCount() override;
553
    GDALRasterBand *GetOverview(int n) override;
554
555
    char **GetMetadataDomainList() override;
556
    virtual const char *GetMetadataItem(const char *pszName,
557
                                        const char *pszDomain = "") override;
558
559
  protected:
560
    CPLErr ReadBlocks(int x, int y, void *buffer, int bx0, int by0, int bx1,
561
                      int by1, int advise_read);
562
    bool IsBlockInCache(int x, int y);
563
    CPLErr AskMiniDriverForBlock(WMSHTTPRequest &request, int x, int y);
564
    CPLErr ReadBlockFromCache(const char *pszKey, int x, int y,
565
                              int to_buffer_band, void *buffer,
566
                              int advise_read);
567
    CPLErr ReadBlockFromFile(const CPLString &soFileName, int x, int y,
568
                             int to_buffer_band, void *buffer, int advise_read);
569
    CPLErr ReadBlockFromDataset(GDALDataset *ds, int x, int y,
570
                                int to_buffer_band, void *buffer,
571
                                int advise_read);
572
    CPLErr EmptyBlock(int x, int y, int to_buffer_band, void *buffer);
573
    static CPLErr ReportWMSException(const char *file_name);
574
575
  protected:
576
    GDALWMSDataset *m_parent_dataset{};
577
    double m_scale{};
578
    std::vector<GDALWMSRasterBand *> m_overviews{};
579
    int m_overview{};
580
    GDALColorInterp m_color_interp{};
581
    int m_nAdviseReadBX0{};
582
    int m_nAdviseReadBY0{};
583
    int m_nAdviseReadBX1{};
584
    int m_nAdviseReadBY1{};
585
};
586
587
#endif /* notdef WMSDRIVER_H_INCLUDED */