/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 | } |