Coverage Report

Created: 2025-12-31 08:30

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