Coverage Report

Created: 2026-08-11 08:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/wms/minidriver_wms.cpp
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) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "wmsdriver.h"
16
#include "minidriver_wms.h"
17
18
#include <algorithm>
19
20
17.8k
WMSMiniDriver_WMS::WMSMiniDriver_WMS() = default;
21
22
17.8k
WMSMiniDriver_WMS::~WMSMiniDriver_WMS() = default;
23
24
static double GetBBoxCoord(const GDALWMSImageRequestInfo &iri, char what)
25
7.84k
{
26
7.84k
    switch (what)
27
7.84k
    {
28
1.96k
        case 'x':
29
1.96k
            return std::min(iri.m_x0, iri.m_x1);
30
1.96k
        case 'y':
31
1.96k
            return std::min(iri.m_y0, iri.m_y1);
32
1.96k
        case 'X':
33
1.96k
            return std::max(iri.m_x0, iri.m_x1);
34
1.96k
        case 'Y':
35
1.96k
            return std::max(iri.m_y0, iri.m_y1);
36
7.84k
    }
37
0
    return 0.0;
38
7.84k
}
39
40
CPLErr WMSMiniDriver_WMS::Initialize(CPLXMLNode *config,
41
                                     CPL_UNUSED char **papszOpenOptions)
42
17.8k
{
43
17.8k
    CPLErr ret = CE_None;
44
45
17.8k
    {
46
17.8k
        const char *version = CPLGetXMLValue(config, "Version", "1.1.0");
47
17.8k
        if (version[0] != '\0')
48
17.8k
        {
49
17.8k
            m_version = version;
50
17.8k
            m_iversion = VersionStringToInt(version);
51
17.8k
            if (m_iversion == -1)
52
5
            {
53
5
                CPLError(CE_Failure, CPLE_AppDefined,
54
5
                         "GDALWMS, WMS mini-driver: Invalid version.");
55
5
                ret = CE_Failure;
56
5
            }
57
17.8k
        }
58
0
        else
59
0
        {
60
0
            CPLError(CE_Failure, CPLE_AppDefined,
61
0
                     "GDALWMS, WMS mini-driver: Version missing.");
62
0
            ret = CE_Failure;
63
0
        }
64
17.8k
    }
65
66
17.8k
    if (ret == CE_None)
67
17.8k
    {
68
17.8k
        const char *base_url = CPLGetXMLValue(config, "ServerURL", "");
69
17.8k
        if (base_url[0] != '\0')
70
17.8k
        {
71
            /* Try the old name */
72
17.8k
            base_url = CPLGetXMLValue(config, "ServerUrl", "");
73
17.8k
        }
74
17.8k
        if (base_url[0] != '\0')
75
17.8k
        {
76
17.8k
            m_base_url = base_url;
77
17.8k
        }
78
0
        else
79
0
        {
80
0
            CPLError(CE_Failure, CPLE_AppDefined,
81
0
                     "GDALWMS, WMS mini-driver: ServerURL missing.");
82
0
            ret = CE_Failure;
83
0
        }
84
17.8k
    }
85
86
17.8k
    if (ret == CE_None)
87
17.8k
    {
88
        /* SRS is WMS version 1.1 and earlier, if SRS is not set use default
89
           unless CRS is set CRS is WMS version 1.3, if CRS is not set use
90
           default unless SRS is set */
91
17.8k
        const char *crs = CPLGetXMLValue(config, "CRS", "");
92
17.8k
        const char *srs = CPLGetXMLValue(config, "SRS", "");
93
17.8k
        if (m_iversion >= VersionStringToInt("1.3"))
94
0
        {
95
            /* Version 1.3 and above */
96
0
            if ((srs[0] != '\0') && (crs[0] == '\0'))
97
0
            {
98
0
                CPLError(CE_Failure, CPLE_AppDefined,
99
0
                         "GDALWMS, WMS mini-driver: WMS version 1.3 and above "
100
0
                         "expects CRS however SRS was set instead.");
101
0
                ret = CE_Failure;
102
0
            }
103
0
            else if (crs[0] != '\0')
104
0
            {
105
0
                m_crs = crs;
106
0
            }
107
0
            else
108
0
            {
109
0
                m_crs = "EPSG:4326";
110
0
            }
111
0
        }
112
17.8k
        else
113
17.8k
        {
114
            /* Version 1.1.1 and below */
115
17.8k
            if ((srs[0] == '\0') && (crs[0] != '\0'))
116
0
            {
117
0
                CPLError(CE_Failure, CPLE_AppDefined,
118
0
                         "GDALWMS, WMS mini-driver: WMS version 1.1.1 and "
119
0
                         "below expects SRS however CRS was set instead.");
120
0
                ret = CE_Failure;
121
0
            }
122
17.8k
            else if (srs[0] != '\0')
123
17.8k
            {
124
17.8k
                m_srs = srs;
125
17.8k
            }
126
0
            else
127
0
            {
128
0
                m_srs = "EPSG:4326";
129
0
            }
130
17.8k
        }
131
17.8k
    }
132
133
17.8k
    if (ret == CE_None)
134
17.8k
    {
135
17.8k
        if (!m_srs.empty())
136
17.8k
        {
137
17.8k
            m_oSRS = ProjToSRS(m_srs);
138
17.8k
        }
139
0
        else if (!m_crs.empty())
140
0
        {
141
0
            m_oSRS = ProjToSRS(m_crs);
142
0
        }
143
17.8k
    }
144
145
17.8k
    if (ret == CE_None)
146
17.8k
    {
147
17.8k
        m_image_format = CPLGetXMLValue(config, "ImageFormat", "image/jpeg");
148
17.8k
        m_info_format =
149
17.8k
            CPLGetConfigOption("WMS_INFO_FORMAT", "application/vnd.ogc.gml");
150
17.8k
        m_layers = CPLGetXMLValue(config, "Layers", "");
151
17.8k
        m_styles = CPLGetXMLValue(config, "Styles", "");
152
17.8k
        m_transparent = CPLGetXMLValue(config, "Transparent", "");
153
        // the transparent flag needs to be "TRUE" or "FALSE" in upper case
154
        // according to the WMS spec so force upper case
155
17.8k
        for (char &ch : m_transparent)
156
89.3k
        {
157
89.3k
            ch = static_cast<char>(toupper(static_cast<unsigned char>(ch)));
158
89.3k
        }
159
17.8k
    }
160
161
17.8k
    if (ret == CE_None)
162
17.8k
    {
163
17.8k
        const char *bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
164
17.8k
        if (bbox_order[0] != '\0')
165
17.8k
        {
166
17.8k
            int i;
167
89.3k
            for (i = 0; i < 4; ++i)
168
71.4k
            {
169
71.4k
                if ((bbox_order[i] != 'x') && (bbox_order[i] != 'y') &&
170
35.7k
                    (bbox_order[i] != 'X') && (bbox_order[i] != 'Y'))
171
0
                    break;
172
71.4k
            }
173
17.8k
            if (i == 4)
174
17.8k
            {
175
17.8k
                m_bbox_order = bbox_order;
176
17.8k
            }
177
0
            else
178
0
            {
179
0
                CPLError(CE_Failure, CPLE_AppDefined,
180
0
                         "GDALWMS, WMS mini-driver: Incorrect BBoxOrder.");
181
0
                ret = CE_Failure;
182
0
            }
183
17.8k
        }
184
0
        else
185
0
        {
186
0
            CPLError(CE_Failure, CPLE_AppDefined,
187
0
                     "GDALWMS, WMS mini-driver: BBoxOrder missing.");
188
0
            ret = CE_Failure;
189
0
        }
190
17.8k
    }
191
192
17.8k
    return ret;
193
17.8k
}
194
195
void WMSMiniDriver_WMS::GetCapabilities(WMSMiniDriverCapabilities *caps)
196
17.8k
{
197
17.8k
    caps->m_has_getinfo = 1;
198
17.8k
}
199
200
void WMSMiniDriver_WMS::BuildURL(CPLString &url,
201
                                 const GDALWMSImageRequestInfo &iri,
202
                                 const char *pszRequest)
203
1.96k
{
204
    // http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&width=1000&height=500&layers=modis,global_mosaic&styles=&srs=EPSG:4326&format=image/jpeg&bbox=-180.000000,-90.000000,180.000000,090.000000
205
1.96k
    url = m_base_url;
206
207
1.96k
    URLPrepare(url);
208
1.96k
    url += "request=";
209
1.96k
    url += pszRequest;
210
211
1.96k
    if (url.ifind("service=") == std::string::npos)
212
678
        url += "&service=WMS";
213
214
1.96k
    url += CPLOPrintf(
215
1.96k
        "&version=%s&layers=%s&styles=%s&format=%s&width=%d&height=%d&bbox=%."
216
1.96k
        "8f,%.8f,%.8f,%.8f",
217
1.96k
        m_version.c_str(), m_layers.c_str(), m_styles.c_str(),
218
1.96k
        m_image_format.c_str(), iri.m_sx, iri.m_sy,
219
1.96k
        GetBBoxCoord(iri, m_bbox_order[0]), GetBBoxCoord(iri, m_bbox_order[1]),
220
1.96k
        GetBBoxCoord(iri, m_bbox_order[2]), GetBBoxCoord(iri, m_bbox_order[3]));
221
222
1.96k
    if (!m_srs.empty())
223
1.96k
        url += CPLOPrintf("&srs=%s", m_srs.c_str());
224
1.96k
    if (!m_crs.empty())
225
0
        url += CPLOPrintf("&crs=%s", m_crs.c_str());
226
1.96k
    if (!m_transparent.empty())
227
1.96k
        url += CPLOPrintf("&transparent=%s", m_transparent.c_str());
228
1.96k
}
229
230
CPLErr WMSMiniDriver_WMS::TiledImageRequest(
231
    WMSHTTPRequest &request, const GDALWMSImageRequestInfo &iri,
232
    CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri)
233
1.96k
{
234
1.96k
    CPLString &url = request.URL;
235
1.96k
    BuildURL(url, iri, "GetMap");
236
1.96k
    return CE_None;
237
1.96k
}
238
239
void WMSMiniDriver_WMS::GetTiledImageInfo(
240
    CPLString &url, const GDALWMSImageRequestInfo &iri,
241
    CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri, int nXInBlock,
242
    int nYInBlock)
243
0
{
244
0
    BuildURL(url, iri, "GetFeatureInfo");
245
0
    url += CPLOPrintf("&query_layers=%s&x=%d&y=%d&info_format=%s",
246
0
                      m_layers.c_str(), nXInBlock, nYInBlock,
247
0
                      m_info_format.c_str());
248
0
}