1 /******************************************************************************
2 * $Id: minidriver_wms.cpp 27942 2014-11-11 00:57:41Z rouault $
3 *
4 * Project: WMS Client Driver
5 * Purpose: Implementation of Dataset and RasterBand classes for WMS
6 * and other similar services.
7 * Author: Adam Nowacki, nowak@xpam.de
8 *
9 ******************************************************************************
10 * Copyright (c) 2007, Adam Nowacki
11 * Copyright (c) 2007-2012, Even Rouault <even dot rouault at mines-paris dot org>
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included
21 * in all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 * DEALINGS IN THE SOFTWARE.
30 ****************************************************************************/
31
32 #include "wmsdriver.h"
33 #include "minidriver_wms.h"
34
CPP_GDALWMSMiniDriverFactory(WMS)35 CPP_GDALWMSMiniDriverFactory(WMS)
36
37 GDALWMSMiniDriver_WMS::GDALWMSMiniDriver_WMS() {
38 }
39
~GDALWMSMiniDriver_WMS()40 GDALWMSMiniDriver_WMS::~GDALWMSMiniDriver_WMS() {
41 }
42
Initialize(CPLXMLNode * config)43 CPLErr GDALWMSMiniDriver_WMS::Initialize(CPLXMLNode *config) {
44 CPLErr ret = CE_None;
45
46 if (ret == CE_None) {
47 const char *version = CPLGetXMLValue(config, "Version", "1.1.0");
48 if (version[0] != '\0') {
49 m_version = version;
50 m_iversion = VersionStringToInt(version);
51 if (m_iversion == -1) {
52 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: Invalid version.");
53 ret = CE_Failure;
54 }
55 } else {
56 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: Version missing.");
57 ret = CE_Failure;
58 }
59 }
60
61 if (ret == CE_None) {
62 const char *base_url = CPLGetXMLValue(config, "ServerURL", "");
63 if (base_url[0] != '\0') {
64 /* Try the old name */
65 base_url = CPLGetXMLValue(config, "ServerUrl", "");
66 }
67 if (base_url[0] != '\0') {
68 m_base_url = base_url;
69 } else {
70 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: ServerURL missing.");
71 ret = CE_Failure;
72 }
73 }
74
75 if (ret == CE_None) {
76 /* SRS is WMS version 1.1 and earlier, if SRS is not set use default unless CRS is set
77 CRS is WMS version 1.3, if CRS is not set use default unless SRS is set */
78 const char *crs = CPLGetXMLValue(config, "CRS", "");
79 const char *srs = CPLGetXMLValue(config, "SRS", "");
80 if (m_iversion >= VersionStringToInt("1.3")) {
81 /* Version 1.3 and above */
82 if ((srs[0] != '\0') && (crs[0] == '\0')) {
83 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: WMS version 1.3 and above expects CRS however SRS was set instead.");
84 ret = CE_Failure;
85 } else if (crs[0] != '\0') {
86 m_crs = crs;
87 } else {
88 m_crs = "EPSG:4326";
89 }
90 } else {
91 /* Version 1.1.1 and below */
92 if ((srs[0] == '\0') && (crs[0] != '\0')) {
93 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: WMS version 1.1.1 and below expects SRS however CRS was set instead.");
94 ret = CE_Failure;
95 } else if (srs[0] != '\0') {
96 m_srs = srs;
97 } else {
98 m_srs = "EPSG:4326";
99 }
100 }
101 }
102
103 if (ret == CE_None) {
104 if (m_srs.size()) {
105 m_projection_wkt = ProjToWKT(m_srs);
106 } else if (m_crs.size()) {
107 m_projection_wkt = ProjToWKT(m_crs);
108 }
109 }
110
111 if (ret == CE_None) {
112 m_image_format = CPLGetXMLValue(config, "ImageFormat", "image/jpeg");
113 m_layers = CPLGetXMLValue(config, "Layers", "");
114 m_styles = CPLGetXMLValue(config, "Styles", "");
115 m_transparent = CPLGetXMLValue(config, "Transparent","");
116 // the transparent flag needs to be "TRUE" or "FALSE" in upper case according to the WMS spec so force upper case
117 for(int i=0; i<(int)m_transparent.size();i++)
118 {
119 m_transparent[i] = (char) toupper(m_transparent[i]);
120 }
121 }
122
123 if (ret == CE_None) {
124 const char *bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
125 if (bbox_order[0] != '\0') {
126 int i;
127 for (i = 0; i < 4; ++i) {
128 if ((bbox_order[i] != 'x') && (bbox_order[i] != 'y') && (bbox_order[i] != 'X') && (bbox_order[i] != 'Y')) break;
129 }
130 if (i == 4) {
131 m_bbox_order = bbox_order;
132 } else {
133 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: Incorrect BBoxOrder.");
134 ret = CE_Failure;
135 }
136 } else {
137 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: BBoxOrder missing.");
138 ret = CE_Failure;
139 }
140 }
141
142 return ret;
143 }
144
GetCapabilities(GDALWMSMiniDriverCapabilities * caps)145 void GDALWMSMiniDriver_WMS::GetCapabilities(GDALWMSMiniDriverCapabilities *caps) {
146 caps->m_capabilities_version = 1;
147 caps->m_has_arb_overviews = 1;
148 caps->m_has_image_request = 1;
149 caps->m_has_tiled_image_requeset = 1;
150 caps->m_max_overview_count = 32;
151 }
152
BuildURL(CPLString * url,const GDALWMSImageRequestInfo & iri,const char * pszRequest)153 void GDALWMSMiniDriver_WMS::BuildURL(CPLString *url, const GDALWMSImageRequestInfo &iri, const char* pszRequest) {
154 // 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
155 *url = m_base_url;
156 if (m_base_url.ifind( "service=") == std::string::npos)
157 URLAppend(url, "&service=WMS");
158 URLAppendF(url, "&request=%s", pszRequest);
159 URLAppendF(url, "&version=%s", m_version.c_str());
160 URLAppendF(url, "&layers=%s", m_layers.c_str());
161 URLAppendF(url, "&styles=%s", m_styles.c_str());
162 if (m_srs.size()) URLAppendF(url, "&srs=%s", m_srs.c_str());
163 if (m_crs.size()) URLAppendF(url, "&crs=%s", m_crs.c_str());
164 if (m_transparent.size()) URLAppendF(url, "&transparent=%s", m_transparent.c_str());
165 URLAppendF(url, "&format=%s", m_image_format.c_str());
166 URLAppendF(url, "&width=%d", iri.m_sx);
167 URLAppendF(url, "&height=%d", iri.m_sy);
168 URLAppendF(url, "&bbox=%.8f,%.8f,%.8f,%.8f",
169 GetBBoxCoord(iri, m_bbox_order[0]), GetBBoxCoord(iri, m_bbox_order[1]),
170 GetBBoxCoord(iri, m_bbox_order[2]), GetBBoxCoord(iri, m_bbox_order[3]));
171 }
172
ImageRequest(CPLString * url,const GDALWMSImageRequestInfo & iri)173 void GDALWMSMiniDriver_WMS::ImageRequest(CPLString *url, const GDALWMSImageRequestInfo &iri) {
174 BuildURL(url, iri, "GetMap");
175 CPLDebug("WMS", "URL = %s", url->c_str());
176 }
177
TiledImageRequest(CPLString * url,const GDALWMSImageRequestInfo & iri,CPL_UNUSED const GDALWMSTiledImageRequestInfo & tiri)178 void GDALWMSMiniDriver_WMS::TiledImageRequest(CPLString *url,
179 const GDALWMSImageRequestInfo &iri,
180 CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri) {
181 ImageRequest(url, iri);
182 }
183
184
GetTiledImageInfo(CPLString * url,const GDALWMSImageRequestInfo & iri,CPL_UNUSED const GDALWMSTiledImageRequestInfo & tiri,int nXInBlock,int nYInBlock)185 void GDALWMSMiniDriver_WMS::GetTiledImageInfo(CPLString *url,
186 const GDALWMSImageRequestInfo &iri,
187 CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri,
188 int nXInBlock,
189 int nYInBlock)
190 {
191 BuildURL(url, iri, "GetFeatureInfo");
192 URLAppendF(url, "&query_layers=%s", m_layers.c_str());
193 URLAppendF(url, "&x=%d", nXInBlock);
194 URLAppendF(url, "&y=%d", nYInBlock);
195 const char* pszInfoFormat = CPLGetConfigOption("WMS_INFO_FORMAT", "application/vnd.ogc.gml");
196 URLAppendF(url, "&info_format=%s", pszInfoFormat);
197
198 CPLDebug("WMS", "URL = %s", url->c_str());
199 }
200
201
GetProjectionInWKT()202 const char *GDALWMSMiniDriver_WMS::GetProjectionInWKT() {
203 return m_projection_wkt.c_str();
204 }
205
GetBBoxCoord(const GDALWMSImageRequestInfo & iri,char what)206 double GDALWMSMiniDriver_WMS::GetBBoxCoord(const GDALWMSImageRequestInfo &iri, char what) {
207 switch (what) {
208 case 'x': return MIN(iri.m_x0, iri.m_x1);
209 case 'y': return MIN(iri.m_y0, iri.m_y1);
210 case 'X': return MAX(iri.m_x0, iri.m_x1);
211 case 'Y': return MAX(iri.m_y0, iri.m_y1);
212 }
213 return 0.0;
214 }
215