Coverage Report

Created: 2025-11-15 08:43

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
26.0k
WMSMiniDriver_WMS::WMSMiniDriver_WMS() = default;
21
22
26.0k
WMSMiniDriver_WMS::~WMSMiniDriver_WMS() = default;
23
24
static double GetBBoxCoord(const GDALWMSImageRequestInfo &iri, char what)
25
9.62k
{
26
9.62k
    switch (what)
27
9.62k
    {
28
2.40k
        case 'x':
29
2.40k
            return std::min(iri.m_x0, iri.m_x1);
30
2.40k
        case 'y':
31
2.40k
            return std::min(iri.m_y0, iri.m_y1);
32
2.40k
        case 'X':
33
2.40k
            return std::max(iri.m_x0, iri.m_x1);
34
2.40k
        case 'Y':
35
2.40k
            return std::max(iri.m_y0, iri.m_y1);
36
9.62k
    }
37
0
    return 0.0;
38
9.62k
}
39
40
CPLErr WMSMiniDriver_WMS::Initialize(CPLXMLNode *config,
41
                                     CPL_UNUSED char **papszOpenOptions)
42
26.0k
{
43
26.0k
    CPLErr ret = CE_None;
44
45
26.0k
    {
46
26.0k
        const char *version = CPLGetXMLValue(config, "Version", "1.1.0");
47
26.0k
        if (version[0] != '\0')
48
26.0k
        {
49
26.0k
            m_version = version;
50
26.0k
            m_iversion = VersionStringToInt(version);
51
26.0k
            if (m_iversion == -1)
52
8
            {
53
8
                CPLError(CE_Failure, CPLE_AppDefined,
54
8
                         "GDALWMS, WMS mini-driver: Invalid version.");
55
8
                ret = CE_Failure;
56
8
            }
57
26.0k
        }
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
26.0k
    }
65
66
26.0k
    if (ret == CE_None)
67
26.0k
    {
68
26.0k
        const char *base_url = CPLGetXMLValue(config, "ServerURL", "");
69
26.0k
        if (base_url[0] != '\0')
70
26.0k
        {
71
            /* Try the old name */
72
26.0k
            base_url = CPLGetXMLValue(config, "ServerUrl", "");
73
26.0k
        }
74
26.0k
        if (base_url[0] != '\0')
75
26.0k
        {
76
26.0k
            m_base_url = base_url;
77
26.0k
        }
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
26.0k
    }
85
86
26.0k
    if (ret == CE_None)
87
26.0k
    {
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
26.0k
        const char *crs = CPLGetXMLValue(config, "CRS", "");
92
26.0k
        const char *srs = CPLGetXMLValue(config, "SRS", "");
93
26.0k
        if (m_iversion >= VersionStringToInt("1.3"))
94
3
        {
95
            /* Version 1.3 and above */
96
3
            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
3
            else if (crs[0] != '\0')
104
3
            {
105
3
                m_crs = crs;
106
3
            }
107
0
            else
108
0
            {
109
0
                m_crs = "EPSG:4326";
110
0
            }
111
3
        }
112
26.0k
        else
113
26.0k
        {
114
            /* Version 1.1.1 and below */
115
26.0k
            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
26.0k
            else if (srs[0] != '\0')
123
26.0k
            {
124
26.0k
                m_srs = srs;
125
26.0k
            }
126
0
            else
127
0
            {
128
0
                m_srs = "EPSG:4326";
129
0
            }
130
26.0k
        }
131
26.0k
    }
132
133
26.0k
    if (ret == CE_None)
134
26.0k
    {
135
26.0k
        if (!m_srs.empty())
136
26.0k
        {
137
26.0k
            m_oSRS = ProjToSRS(m_srs);
138
26.0k
        }
139
3
        else if (!m_crs.empty())
140
3
        {
141
3
            m_oSRS = ProjToSRS(m_crs);
142
3
        }
143
26.0k
    }
144
145
26.0k
    if (ret == CE_None)
146
26.0k
    {
147
26.0k
        m_image_format = CPLGetXMLValue(config, "ImageFormat", "image/jpeg");
148
26.0k
        m_info_format =
149
26.0k
            CPLGetConfigOption("WMS_INFO_FORMAT", "application/vnd.ogc.gml");
150
26.0k
        m_layers = CPLGetXMLValue(config, "Layers", "");
151
26.0k
        m_styles = CPLGetXMLValue(config, "Styles", "");
152
26.0k
        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
26.0k
        for (char &ch : m_transparent)
156
130k
        {
157
130k
            ch = static_cast<char>(toupper(static_cast<unsigned char>(ch)));
158
130k
        }
159
26.0k
    }
160
161
26.0k
    if (ret == CE_None)
162
26.0k
    {
163
26.0k
        const char *bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
164
26.0k
        if (bbox_order[0] != '\0')
165
26.0k
        {
166
26.0k
            int i;
167
130k
            for (i = 0; i < 4; ++i)
168
104k
            {
169
104k
                if ((bbox_order[i] != 'x') && (bbox_order[i] != 'y') &&
170
52.1k
                    (bbox_order[i] != 'X') && (bbox_order[i] != 'Y'))
171
0
                    break;
172
104k
            }
173
26.0k
            if (i == 4)
174
26.0k
            {
175
26.0k
                m_bbox_order = bbox_order;
176
26.0k
            }
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
26.0k
        }
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
26.0k
    }
191
192
26.0k
    return ret;
193
26.0k
}
194
195
void WMSMiniDriver_WMS::GetCapabilities(WMSMiniDriverCapabilities *caps)
196
26.0k
{
197
26.0k
    caps->m_has_getinfo = 1;
198
26.0k
}
199
200
void WMSMiniDriver_WMS::BuildURL(CPLString &url,
201
                                 const GDALWMSImageRequestInfo &iri,
202
                                 const char *pszRequest)
203
2.40k
{
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
2.40k
    url = m_base_url;
206
207
2.40k
    URLPrepare(url);
208
2.40k
    url += "request=";
209
2.40k
    url += pszRequest;
210
211
2.40k
    if (url.ifind("service=") == std::string::npos)
212
868
        url += "&service=WMS";
213
214
2.40k
    url += CPLOPrintf(
215
2.40k
        "&version=%s&layers=%s&styles=%s&format=%s&width=%d&height=%d&bbox=%."
216
2.40k
        "8f,%.8f,%.8f,%.8f",
217
2.40k
        m_version.c_str(), m_layers.c_str(), m_styles.c_str(),
218
2.40k
        m_image_format.c_str(), iri.m_sx, iri.m_sy,
219
2.40k
        GetBBoxCoord(iri, m_bbox_order[0]), GetBBoxCoord(iri, m_bbox_order[1]),
220
2.40k
        GetBBoxCoord(iri, m_bbox_order[2]), GetBBoxCoord(iri, m_bbox_order[3]));
221
222
2.40k
    if (!m_srs.empty())
223
2.40k
        url += CPLOPrintf("&srs=%s", m_srs.c_str());
224
2.40k
    if (!m_crs.empty())
225
3
        url += CPLOPrintf("&crs=%s", m_crs.c_str());
226
2.40k
    if (!m_transparent.empty())
227
2.40k
        url += CPLOPrintf("&transparent=%s", m_transparent.c_str());
228
2.40k
}
229
230
CPLErr WMSMiniDriver_WMS::TiledImageRequest(
231
    WMSHTTPRequest &request, const GDALWMSImageRequestInfo &iri,
232
    CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri)
233
2.40k
{
234
2.40k
    CPLString &url = request.URL;
235
2.40k
    BuildURL(url, iri, "GetMap");
236
2.40k
    return CE_None;
237
2.40k
}
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
}