1 : /******************************************************************************
2 : * $Id: wmsmetadataset.cpp 22576 2011-06-24 13:14:21Z warmerdam $
3 : *
4 : * Project: WMS Client Driver
5 : * Purpose: Definition of GDALWMSMetaDataset class
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, Even Rouault, <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "wmsmetadataset.h"
31 :
32 : int VersionStringToInt(const char *version);
33 :
34 : /************************************************************************/
35 : /* GDALWMSMetaDataset() */
36 : /************************************************************************/
37 :
38 4 : GDALWMSMetaDataset::GDALWMSMetaDataset() : papszSubDatasets(NULL)
39 : {
40 4 : }
41 :
42 : /************************************************************************/
43 : /* ~GDALWMSMetaDataset() */
44 : /************************************************************************/
45 :
46 4 : GDALWMSMetaDataset::~GDALWMSMetaDataset()
47 : {
48 4 : CSLDestroy(papszSubDatasets);
49 4 : }
50 :
51 : /************************************************************************/
52 : /* AddSubDataset() */
53 : /************************************************************************/
54 :
55 184 : void GDALWMSMetaDataset::AddSubDataset(const char* pszName,
56 : const char* pszDesc)
57 : {
58 : char szName[80];
59 184 : int nCount = CSLCount(papszSubDatasets ) / 2;
60 :
61 184 : sprintf( szName, "SUBDATASET_%d_NAME", nCount+1 );
62 : papszSubDatasets =
63 184 : CSLSetNameValue( papszSubDatasets, szName, pszName );
64 :
65 184 : sprintf( szName, "SUBDATASET_%d_DESC", nCount+1 );
66 : papszSubDatasets =
67 184 : CSLSetNameValue( papszSubDatasets, szName, pszDesc);
68 184 : }
69 :
70 : /************************************************************************/
71 : /* DownloadGetCapabilities() */
72 : /************************************************************************/
73 :
74 2 : GDALDataset *GDALWMSMetaDataset::DownloadGetCapabilities(GDALOpenInfo *poOpenInfo)
75 : {
76 2 : const char* pszURL = poOpenInfo->pszFilename;
77 2 : if (EQUALN(pszURL, "WMS:", 4))
78 2 : pszURL += 4;
79 :
80 2 : CPLString osFormat = CPLURLGetValue(pszURL, "FORMAT");
81 2 : CPLString osTransparent = CPLURLGetValue(pszURL, "TRANSPARENT");
82 2 : CPLString osVersion = CPLURLGetValue(pszURL, "VERSION");
83 :
84 2 : if (osVersion.size() == 0)
85 2 : osVersion = "1.1.1";
86 :
87 2 : CPLString osURL(pszURL);
88 2 : osURL = CPLURLAddKVP(osURL, "SERVICE", "WMS");
89 2 : osURL = CPLURLAddKVP(osURL, "VERSION", osVersion);
90 2 : osURL = CPLURLAddKVP(osURL, "REQUEST", "GetCapabilities");
91 : /* Remove all other keywords */
92 2 : osURL = CPLURLAddKVP(osURL, "LAYERS", NULL);
93 2 : osURL = CPLURLAddKVP(osURL, "SRS", NULL);
94 2 : osURL = CPLURLAddKVP(osURL, "CRS", NULL);
95 2 : osURL = CPLURLAddKVP(osURL, "BBOX", NULL);
96 2 : osURL = CPLURLAddKVP(osURL, "FORMAT", NULL);
97 2 : osURL = CPLURLAddKVP(osURL, "TRANSPARENT", NULL);
98 2 : osURL = CPLURLAddKVP(osURL, "STYLES", NULL);
99 2 : osURL = CPLURLAddKVP(osURL, "WIDTH", NULL);
100 2 : osURL = CPLURLAddKVP(osURL, "HEIGHT", NULL);
101 :
102 2 : CPLHTTPResult* psResult = CPLHTTPFetch( osURL, NULL );
103 2 : if (psResult == NULL)
104 : {
105 0 : return NULL;
106 : }
107 2 : if (psResult->nStatus != 0 || psResult->pszErrBuf != NULL)
108 : {
109 : CPLError(CE_Failure, CPLE_AppDefined,
110 : "Error returned by server : %s (%d)",
111 : (psResult->pszErrBuf) ? psResult->pszErrBuf : "unknown",
112 2 : psResult->nStatus);
113 2 : CPLHTTPDestroyResult(psResult);
114 2 : return NULL;
115 : }
116 0 : if (psResult->pabyData == NULL)
117 : {
118 : CPLError(CE_Failure, CPLE_AppDefined,
119 0 : "Empty content returned by server");
120 0 : CPLHTTPDestroyResult(psResult);
121 0 : return NULL;
122 : }
123 :
124 0 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
125 0 : if (psXML == NULL)
126 : {
127 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
128 0 : psResult->pabyData);
129 0 : CPLHTTPDestroyResult(psResult);
130 0 : return NULL;
131 : }
132 :
133 0 : GDALDataset* poRet = AnalyzeGetCapabilities(psXML, osFormat, osTransparent);
134 :
135 0 : CPLHTTPDestroyResult(psResult);
136 0 : CPLDestroyXMLNode( psXML );
137 :
138 0 : return poRet;
139 : }
140 :
141 :
142 : /************************************************************************/
143 : /* DownloadGetTileService() */
144 : /************************************************************************/
145 :
146 2 : GDALDataset *GDALWMSMetaDataset::DownloadGetTileService(GDALOpenInfo *poOpenInfo)
147 : {
148 2 : const char* pszURL = poOpenInfo->pszFilename;
149 2 : if (EQUALN(pszURL, "WMS:", 4))
150 2 : pszURL += 4;
151 :
152 2 : CPLString osURL(pszURL);
153 2 : osURL = CPLURLAddKVP(osURL, "SERVICE", "WMS");
154 2 : osURL = CPLURLAddKVP(osURL, "REQUEST", "GetTileService");
155 : /* Remove all other keywords */
156 2 : osURL = CPLURLAddKVP(osURL, "VERSION", NULL);
157 2 : osURL = CPLURLAddKVP(osURL, "LAYERS", NULL);
158 2 : osURL = CPLURLAddKVP(osURL, "SRS", NULL);
159 2 : osURL = CPLURLAddKVP(osURL, "CRS", NULL);
160 2 : osURL = CPLURLAddKVP(osURL, "BBOX", NULL);
161 2 : osURL = CPLURLAddKVP(osURL, "FORMAT", NULL);
162 2 : osURL = CPLURLAddKVP(osURL, "TRANSPARENT", NULL);
163 2 : osURL = CPLURLAddKVP(osURL, "STYLES", NULL);
164 2 : osURL = CPLURLAddKVP(osURL, "WIDTH", NULL);
165 2 : osURL = CPLURLAddKVP(osURL, "HEIGHT", NULL);
166 :
167 2 : CPLHTTPResult* psResult = CPLHTTPFetch( osURL, NULL );
168 2 : if (psResult == NULL)
169 : {
170 0 : return NULL;
171 : }
172 2 : if (psResult->nStatus != 0 || psResult->pszErrBuf != NULL)
173 : {
174 : CPLError(CE_Failure, CPLE_AppDefined,
175 : "Error returned by server : %s (%d)",
176 : (psResult->pszErrBuf) ? psResult->pszErrBuf : "unknown",
177 0 : psResult->nStatus);
178 0 : CPLHTTPDestroyResult(psResult);
179 0 : return NULL;
180 : }
181 2 : if (psResult->pabyData == NULL)
182 : {
183 : CPLError(CE_Failure, CPLE_AppDefined,
184 0 : "Empty content returned by server");
185 0 : CPLHTTPDestroyResult(psResult);
186 0 : return NULL;
187 : }
188 :
189 2 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
190 2 : if (psXML == NULL)
191 : {
192 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
193 0 : psResult->pabyData);
194 0 : CPLHTTPDestroyResult(psResult);
195 0 : return NULL;
196 : }
197 :
198 2 : GDALDataset* poRet = AnalyzeGetTileService(psXML);
199 :
200 2 : CPLHTTPDestroyResult(psResult);
201 2 : CPLDestroyXMLNode( psXML );
202 :
203 2 : return poRet;
204 : }
205 : /************************************************************************/
206 : /* GetMetadata() */
207 : /************************************************************************/
208 :
209 4 : char **GDALWMSMetaDataset::GetMetadata( const char *pszDomain )
210 :
211 : {
212 4 : if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
213 4 : return papszSubDatasets;
214 :
215 0 : return GDALPamDataset::GetMetadata( pszDomain );
216 : }
217 :
218 : /************************************************************************/
219 : /* AddSubDataset() */
220 : /************************************************************************/
221 :
222 0 : void GDALWMSMetaDataset::AddSubDataset( const char* pszLayerName,
223 : const char* pszTitle,
224 : const char* pszAbstract,
225 : const char* pszSRS,
226 : const char* pszMinX,
227 : const char* pszMinY,
228 : const char* pszMaxX,
229 : const char* pszMaxY,
230 : CPLString osFormat,
231 : CPLString osTransparent)
232 :
233 : {
234 0 : CPLString osSubdatasetName = "WMS:";
235 0 : osSubdatasetName += osGetURL;
236 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SERVICE", "WMS");
237 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "VERSION", osVersion);
238 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "REQUEST", "GetMap");
239 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "LAYERS", pszLayerName);
240 0 : if(VersionStringToInt(osVersion.c_str())>= VersionStringToInt("1.3.0"))
241 : {
242 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "CRS", pszSRS);
243 : /* FIXME: this should apply to all SRS that need axis inversion */
244 0 : if (strcmp(pszSRS, "EPSG:4326") == 0)
245 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "BBOXORDER", "yxYX");
246 : }
247 : else
248 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SRS", pszSRS);
249 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "BBOX",
250 0 : CPLSPrintf("%s,%s,%s,%s", pszMinX, pszMinY, pszMaxX, pszMaxY));
251 0 : if (osFormat.size() != 0)
252 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "FORMAT",
253 0 : osFormat);
254 0 : if (osTransparent.size() != 0)
255 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TRANSPARENT",
256 0 : osTransparent);
257 :
258 0 : if (pszTitle)
259 : {
260 0 : if (osXMLEncoding.size() != 0 &&
261 : osXMLEncoding != "utf-8" &&
262 : osXMLEncoding != "UTF-8")
263 : {
264 : char* pszRecodedTitle = CPLRecode(pszTitle, osXMLEncoding.c_str(),
265 0 : CPL_ENC_UTF8);
266 0 : if (pszRecodedTitle)
267 0 : AddSubDataset(osSubdatasetName, pszRecodedTitle);
268 : else
269 0 : AddSubDataset(osSubdatasetName, pszTitle);
270 0 : CPLFree(pszRecodedTitle);
271 : }
272 : else
273 : {
274 0 : AddSubDataset(osSubdatasetName, pszTitle);
275 : }
276 : }
277 : else
278 : {
279 0 : AddSubDataset(osSubdatasetName, pszLayerName);
280 0 : }
281 0 : }
282 :
283 :
284 : /************************************************************************/
285 : /* AddWMSCSubDataset() */
286 : /************************************************************************/
287 :
288 0 : void GDALWMSMetaDataset::AddWMSCSubDataset(WMSCTileSetDesc& oWMSCTileSetDesc,
289 : const char* pszTitle,
290 : CPLString osTransparent)
291 : {
292 0 : CPLString osSubdatasetName = "WMS:";
293 0 : osSubdatasetName += osGetURL;
294 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SERVICE", "WMS");
295 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "VERSION", osVersion);
296 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "REQUEST", "GetMap");
297 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "LAYERS", oWMSCTileSetDesc.osLayers);
298 0 : if(VersionStringToInt(osVersion.c_str())>= VersionStringToInt("1.3.0"))
299 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "CRS", oWMSCTileSetDesc.osSRS);
300 : else
301 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SRS", oWMSCTileSetDesc.osSRS);
302 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "BBOX",
303 : CPLSPrintf("%s,%s,%s,%s", oWMSCTileSetDesc.osMinX.c_str(),
304 : oWMSCTileSetDesc.osMinY.c_str(),
305 : oWMSCTileSetDesc.osMaxX.c_str(),
306 0 : oWMSCTileSetDesc.osMaxY.c_str()));
307 :
308 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "FORMAT", oWMSCTileSetDesc.osFormat);
309 0 : if (osTransparent.size() != 0)
310 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TRANSPARENT",
311 0 : osTransparent);
312 0 : if (oWMSCTileSetDesc.nTileWidth != oWMSCTileSetDesc.nTileHeight)
313 : CPLDebug("WMS", "Weird: nTileWidth != nTileHeight for %s",
314 0 : oWMSCTileSetDesc.osLayers.c_str());
315 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TILESIZE",
316 0 : CPLSPrintf("%d", oWMSCTileSetDesc.nTileWidth));
317 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "OVERVIEWCOUNT",
318 0 : CPLSPrintf("%d", oWMSCTileSetDesc.nResolutions - 1));
319 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "MINRESOLUTION",
320 0 : CPLSPrintf("%.16f", oWMSCTileSetDesc.dfMinResolution));
321 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TILED", "true");
322 :
323 0 : if (pszTitle)
324 : {
325 0 : if (osXMLEncoding.size() != 0 &&
326 : osXMLEncoding != "utf-8" &&
327 : osXMLEncoding != "UTF-8")
328 : {
329 : char* pszRecodedTitle = CPLRecode(pszTitle, osXMLEncoding.c_str(),
330 0 : CPL_ENC_UTF8);
331 0 : if (pszRecodedTitle)
332 0 : AddSubDataset(osSubdatasetName, pszRecodedTitle);
333 : else
334 0 : AddSubDataset(osSubdatasetName, pszTitle);
335 0 : CPLFree(pszRecodedTitle);
336 : }
337 : else
338 : {
339 0 : AddSubDataset(osSubdatasetName, pszTitle);
340 : }
341 : }
342 : else
343 : {
344 0 : AddSubDataset(osSubdatasetName, oWMSCTileSetDesc.osLayers);
345 0 : }
346 0 : }
347 :
348 : /************************************************************************/
349 : /* ExploreLayer() */
350 : /************************************************************************/
351 :
352 0 : void GDALWMSMetaDataset::ExploreLayer(CPLXMLNode* psXML,
353 : CPLString osFormat,
354 : CPLString osTransparent,
355 : const char* pszSRS,
356 : const char* pszMinX,
357 : const char* pszMinY,
358 : const char* pszMaxX,
359 : const char* pszMaxY)
360 : {
361 0 : const char* pszName = CPLGetXMLValue(psXML, "Name", NULL);
362 0 : const char* pszTitle = CPLGetXMLValue(psXML, "Title", NULL);
363 0 : const char* pszAbstract = CPLGetXMLValue(psXML, "Abstract", NULL);
364 :
365 0 : const char* pszSRSLocal = NULL;
366 0 : const char* pszMinXLocal = NULL;
367 0 : const char* pszMinYLocal = NULL;
368 0 : const char* pszMaxXLocal = NULL;
369 0 : const char* pszMaxYLocal = NULL;
370 :
371 : const char* pszSRSTagName =
372 0 : VersionStringToInt(osVersion.c_str()) >= VersionStringToInt("1.3.0") ? "CRS" : "SRS";
373 :
374 : /* Use local bounding box if available, otherwise use the one */
375 : /* that comes from an upper layer */
376 : /* such as in http://neowms.sci.gsfc.nasa.gov/wms/wms */
377 0 : CPLXMLNode* psSRS = CPLGetXMLNode( psXML, "BoundingBox" );
378 0 : if (psSRS == NULL)
379 : {
380 0 : psSRS = CPLGetXMLNode( psXML, "LatLonBoundingBox" );
381 0 : pszSRSLocal = CPLGetXMLValue(psXML, pszSRSTagName, NULL);
382 0 : if (pszSRSLocal == NULL)
383 0 : pszSRSLocal = "EPSG:4326";
384 : }
385 : else
386 0 : pszSRSLocal = CPLGetXMLValue(psSRS, pszSRSTagName, NULL);
387 :
388 0 : if (pszSRSLocal != NULL && psSRS != NULL)
389 : {
390 0 : pszMinXLocal = CPLGetXMLValue(psSRS, "minx", NULL);
391 0 : pszMinYLocal = CPLGetXMLValue(psSRS, "miny", NULL);
392 0 : pszMaxXLocal = CPLGetXMLValue(psSRS, "maxx", NULL);
393 0 : pszMaxYLocal = CPLGetXMLValue(psSRS, "maxy", NULL);
394 :
395 0 : if (pszMinXLocal && pszMinYLocal && pszMaxXLocal && pszMaxYLocal)
396 : {
397 0 : pszSRS = pszSRSLocal;
398 0 : pszMinX = pszMinXLocal;
399 0 : pszMinY = pszMinYLocal;
400 0 : pszMaxX = pszMaxXLocal;
401 0 : pszMaxY = pszMaxYLocal;
402 : }
403 : }
404 :
405 0 : if (pszName != NULL && pszSRS && pszMinX && pszMinY && pszMaxX && pszMaxY)
406 : {
407 0 : CPLString osLocalTransparent(osTransparent);
408 0 : if (osLocalTransparent.size() == 0)
409 : {
410 0 : const char* pszOpaque = CPLGetXMLValue(psXML, "opaque", "0");
411 0 : if (EQUAL(pszOpaque, "1"))
412 0 : osLocalTransparent = "FALSE";
413 : }
414 :
415 0 : WMSCKeyType oWMSCKey(pszName, pszSRS);
416 0 : std::map<WMSCKeyType, WMSCTileSetDesc>::iterator oIter = osMapWMSCTileSet.find(oWMSCKey);
417 0 : if (oIter != osMapWMSCTileSet.end())
418 : {
419 0 : AddWMSCSubDataset(oIter->second, pszTitle, osLocalTransparent);
420 : }
421 : else
422 : {
423 : AddSubDataset(pszName, pszTitle, pszAbstract,
424 : pszSRS, pszMinX, pszMinY,
425 0 : pszMaxX, pszMaxY, osFormat, osLocalTransparent);
426 0 : }
427 : }
428 :
429 0 : CPLXMLNode* psIter = psXML->psChild;
430 0 : for(; psIter != NULL; psIter = psIter->psNext)
431 : {
432 0 : if (psIter->eType == CXT_Element)
433 : {
434 0 : if (EQUAL(psIter->pszValue, "Layer"))
435 : ExploreLayer(psIter, osFormat, osTransparent,
436 0 : pszSRS, pszMinX, pszMinY, pszMaxX, pszMaxY);
437 : }
438 : }
439 0 : }
440 :
441 : /************************************************************************/
442 : /* ParseWMSCTileSets() */
443 : /************************************************************************/
444 :
445 0 : void GDALWMSMetaDataset::ParseWMSCTileSets(CPLXMLNode* psXML)
446 : {
447 0 : CPLXMLNode* psIter = psXML->psChild;
448 0 : for(;psIter;psIter = psIter->psNext)
449 : {
450 0 : if (psIter->eType == CXT_Element && EQUAL(psIter->pszValue, "TileSet"))
451 : {
452 0 : const char* pszSRS = CPLGetXMLValue(psIter, "SRS", NULL);
453 0 : if (pszSRS == NULL)
454 0 : continue;
455 :
456 0 : CPLXMLNode* psBoundingBox = CPLGetXMLNode( psIter, "BoundingBox" );
457 0 : if (psBoundingBox == NULL)
458 0 : continue;
459 :
460 0 : const char* pszMinX = CPLGetXMLValue(psBoundingBox, "minx", NULL);
461 0 : const char* pszMinY = CPLGetXMLValue(psBoundingBox, "miny", NULL);
462 0 : const char* pszMaxX = CPLGetXMLValue(psBoundingBox, "maxx", NULL);
463 0 : const char* pszMaxY = CPLGetXMLValue(psBoundingBox, "maxy", NULL);
464 0 : if (pszMinX == NULL || pszMinY == NULL || pszMaxX == NULL || pszMaxY == NULL)
465 0 : continue;
466 :
467 0 : double dfMinX = CPLAtofM(pszMinX);
468 0 : double dfMinY = CPLAtofM(pszMinY);
469 0 : double dfMaxX = CPLAtofM(pszMaxX);
470 0 : double dfMaxY = CPLAtofM(pszMaxY);
471 0 : if (dfMaxY <= dfMinY || dfMaxX <= dfMinX)
472 0 : continue;
473 :
474 0 : const char* pszFormat = CPLGetXMLValue( psIter, "Format", NULL );
475 0 : if (pszFormat == NULL)
476 0 : continue;
477 0 : if (strstr(pszFormat, "kml"))
478 0 : continue;
479 :
480 0 : const char* pszTileWidth = CPLGetXMLValue(psIter, "Width", NULL);
481 0 : const char* pszTileHeight = CPLGetXMLValue(psIter, "Height", NULL);
482 0 : if (pszTileWidth == NULL || pszTileHeight == NULL)
483 0 : continue;
484 :
485 0 : int nTileWidth = atoi(pszTileWidth);
486 0 : int nTileHeight = atoi(pszTileHeight);
487 0 : if (nTileWidth < 128 || nTileHeight < 128)
488 0 : continue;
489 :
490 0 : const char* pszLayers = CPLGetXMLValue(psIter, "Layers", NULL);
491 0 : if (pszLayers == NULL)
492 0 : continue;
493 :
494 0 : const char* pszResolutions = CPLGetXMLValue(psIter, "Resolutions", NULL);
495 0 : if (pszResolutions == NULL)
496 0 : continue;
497 0 : char** papszTokens = CSLTokenizeStringComplex(pszResolutions, " ", 0, 0);
498 0 : double dfMinResolution = 0;
499 : int i;
500 0 : for(i=0; papszTokens && papszTokens[i]; i++)
501 : {
502 0 : double dfResolution = CPLAtofM(papszTokens[i]);
503 0 : if (i==0 || dfResolution < dfMinResolution)
504 0 : dfMinResolution = dfResolution;
505 : }
506 0 : CSLDestroy(papszTokens);
507 0 : int nResolutions = i;
508 0 : if (nResolutions == 0)
509 0 : continue;
510 :
511 0 : const char* pszStyles = CPLGetXMLValue(psIter, "Styles", "");
512 :
513 : /* http://demo.opengeo.org/geoserver/gwc/service/wms?tiled=TRUE&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities */
514 : /* has different variations of formats for the same (formats, SRS) tuple, so just */
515 : /* keep the first one which is a png format */
516 0 : WMSCKeyType oWMSCKey(pszLayers, pszSRS);
517 0 : std::map<WMSCKeyType, WMSCTileSetDesc>::iterator oIter = osMapWMSCTileSet.find(oWMSCKey);
518 0 : if (oIter != osMapWMSCTileSet.end())
519 0 : continue;
520 :
521 0 : WMSCTileSetDesc oWMSCTileSet;
522 0 : oWMSCTileSet.osLayers = pszLayers;
523 0 : oWMSCTileSet.osSRS = pszSRS;
524 0 : oWMSCTileSet.osMinX = pszMinX;
525 0 : oWMSCTileSet.osMinY = pszMinY;
526 0 : oWMSCTileSet.osMaxX = pszMaxX;
527 0 : oWMSCTileSet.osMaxY = pszMaxY;
528 0 : oWMSCTileSet.dfMinX = dfMinX;
529 0 : oWMSCTileSet.dfMinY = dfMinY;
530 0 : oWMSCTileSet.dfMaxX = dfMaxX;
531 0 : oWMSCTileSet.dfMaxY = dfMaxY;
532 0 : oWMSCTileSet.nResolutions = nResolutions;
533 0 : oWMSCTileSet.dfMinResolution = dfMinResolution;
534 0 : oWMSCTileSet.osFormat = pszFormat;
535 0 : oWMSCTileSet.osStyle = pszStyles;
536 0 : oWMSCTileSet.nTileWidth = nTileWidth;
537 0 : oWMSCTileSet.nTileHeight = nTileHeight;
538 :
539 0 : osMapWMSCTileSet[oWMSCKey] = oWMSCTileSet;
540 : }
541 : }
542 0 : }
543 :
544 : /************************************************************************/
545 : /* AnalyzeGetCapabilities() */
546 : /************************************************************************/
547 :
548 0 : GDALDataset* GDALWMSMetaDataset::AnalyzeGetCapabilities(CPLXMLNode* psXML,
549 : CPLString osFormat,
550 : CPLString osTransparent)
551 : {
552 0 : const char* pszEncoding = NULL;
553 0 : if (psXML->eType == CXT_Element && strcmp(psXML->pszValue, "?xml") == 0)
554 0 : pszEncoding = CPLGetXMLValue(psXML, "encoding", NULL);
555 :
556 0 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=WMT_MS_Capabilities" );
557 0 : if (psRoot == NULL)
558 0 : psRoot = CPLGetXMLNode( psXML, "=WMS_Capabilities" );
559 0 : if (psRoot == NULL)
560 0 : return NULL;
561 0 : CPLXMLNode* psCapability = CPLGetXMLNode(psRoot, "Capability");
562 0 : if (psCapability == NULL)
563 0 : return NULL;
564 :
565 : CPLXMLNode* psOnlineResource = CPLGetXMLNode(psCapability,
566 0 : "Request.GetMap.DCPType.HTTP.Get.OnlineResource");
567 0 : if (psOnlineResource == NULL)
568 0 : return NULL;
569 : const char* pszGetURL =
570 0 : CPLGetXMLValue(psOnlineResource, "xlink:href", NULL);
571 0 : if (pszGetURL == NULL)
572 0 : return NULL;
573 :
574 0 : CPLXMLNode* psLayer = CPLGetXMLNode(psCapability, "Layer");
575 0 : if (psLayer == NULL)
576 0 : return NULL;
577 :
578 : CPLXMLNode* psVendorSpecificCapabilities =
579 0 : CPLGetXMLNode(psCapability, "VendorSpecificCapabilities");
580 :
581 0 : GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset();
582 0 : const char* pszVersion = CPLGetXMLValue(psRoot, "version", NULL);
583 0 : if (pszVersion)
584 0 : poDS->osVersion = pszVersion;
585 : else
586 0 : poDS->osVersion = "1.1.1";
587 0 : poDS->osGetURL = pszGetURL;
588 0 : poDS->osXMLEncoding = pszEncoding ? pszEncoding : "";
589 0 : if (psVendorSpecificCapabilities)
590 0 : poDS->ParseWMSCTileSets(psVendorSpecificCapabilities);
591 0 : poDS->ExploreLayer(psLayer, osFormat, osTransparent);
592 :
593 0 : return poDS;
594 : }
595 :
596 : /************************************************************************/
597 : /* AddTiledSubDataset() */
598 : /************************************************************************/
599 :
600 106 : void GDALWMSMetaDataset::AddTiledSubDataset(const char* pszTiledGroupName,
601 : const char* pszTitle)
602 : {
603 106 : CPLString osSubdatasetName = "<GDAL_WMS><Service name=\"TiledWMS\"><ServerUrl>";
604 106 : osSubdatasetName += osGetURL;
605 106 : osSubdatasetName += "</ServerUrl><TiledGroupName>";
606 106 : osSubdatasetName += pszTiledGroupName;
607 106 : osSubdatasetName += "</TiledGroupName></Service></GDAL_WMS>";
608 :
609 106 : if (pszTitle)
610 : {
611 106 : if (osXMLEncoding.size() != 0 &&
612 : osXMLEncoding != "utf-8" &&
613 : osXMLEncoding != "UTF-8")
614 : {
615 : char* pszRecodedTitle = CPLRecode(pszTitle, osXMLEncoding.c_str(),
616 0 : CPL_ENC_UTF8);
617 0 : if (pszRecodedTitle)
618 0 : AddSubDataset(osSubdatasetName, pszRecodedTitle);
619 : else
620 0 : AddSubDataset(osSubdatasetName, pszTitle);
621 0 : CPLFree(pszRecodedTitle);
622 : }
623 : else
624 : {
625 106 : AddSubDataset(osSubdatasetName, pszTitle);
626 : }
627 : }
628 : else
629 : {
630 0 : AddSubDataset(osSubdatasetName, pszTiledGroupName);
631 106 : }
632 106 : }
633 :
634 : /************************************************************************/
635 : /* AnalyzeGetTileServiceRecurse() */
636 : /************************************************************************/
637 :
638 10 : void GDALWMSMetaDataset::AnalyzeGetTileServiceRecurse(CPLXMLNode* psXML)
639 : {
640 10 : CPLXMLNode* psIter = psXML->psChild;
641 152 : for(; psIter != NULL; psIter = psIter->psNext)
642 : {
643 248 : if (psIter->eType == CXT_Element &&
644 : EQUAL(psIter->pszValue, "TiledGroup"))
645 : {
646 106 : const char* pszName = CPLGetXMLValue(psIter, "Name", NULL);
647 106 : const char* pszTitle = CPLGetXMLValue(psIter, "Title", NULL);
648 106 : if (pszName)
649 106 : AddTiledSubDataset(pszName, pszTitle);
650 : }
651 36 : else if (psIter->eType == CXT_Element &&
652 : EQUAL(psIter->pszValue, "TiledGroups"))
653 : {
654 8 : AnalyzeGetTileServiceRecurse(psIter);
655 : }
656 : }
657 10 : }
658 :
659 : /************************************************************************/
660 : /* AnalyzeGetTileService() */
661 : /************************************************************************/
662 :
663 2 : GDALDataset* GDALWMSMetaDataset::AnalyzeGetTileService(CPLXMLNode* psXML)
664 : {
665 2 : const char* pszEncoding = NULL;
666 2 : if (psXML->eType == CXT_Element && strcmp(psXML->pszValue, "?xml") == 0)
667 0 : pszEncoding = CPLGetXMLValue(psXML, "encoding", NULL);
668 :
669 2 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=WMS_Tile_Service" );
670 2 : if (psRoot == NULL)
671 0 : return NULL;
672 2 : CPLXMLNode* psTiledPatterns = CPLGetXMLNode(psRoot, "TiledPatterns");
673 2 : if (psTiledPatterns == NULL)
674 0 : return NULL;
675 :
676 : const char* pszURL = CPLGetXMLValue(psTiledPatterns,
677 2 : "OnlineResource.xlink:href", NULL);
678 2 : if (pszURL == NULL)
679 0 : return NULL;
680 :
681 2 : GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset();
682 4 : poDS->osGetURL = pszURL;
683 2 : poDS->osXMLEncoding = pszEncoding ? pszEncoding : "";
684 :
685 2 : poDS->AnalyzeGetTileServiceRecurse(psTiledPatterns);
686 :
687 2 : return poDS;
688 : }
689 :
690 : /************************************************************************/
691 : /* AnalyzeTileMapService() */
692 : /************************************************************************/
693 :
694 2 : GDALDataset* GDALWMSMetaDataset::AnalyzeTileMapService(CPLXMLNode* psXML)
695 : {
696 2 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TileMapService" );
697 2 : if (psRoot == NULL)
698 0 : return NULL;
699 2 : CPLXMLNode* psTileMaps = CPLGetXMLNode(psRoot, "TileMaps");
700 2 : if (psTileMaps == NULL)
701 0 : return NULL;
702 :
703 2 : GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset();
704 :
705 2 : CPLXMLNode* psIter = psTileMaps->psChild;
706 80 : for(; psIter != NULL; psIter = psIter->psNext)
707 : {
708 78 : if (psIter->eType == CXT_Element &&
709 : EQUAL(psIter->pszValue, "TileMap"))
710 : {
711 78 : const char* pszHref = CPLGetXMLValue(psIter, "href", NULL);
712 78 : const char* pszTitle = CPLGetXMLValue(psIter, "title", NULL);
713 78 : if (pszHref && pszTitle)
714 : {
715 78 : CPLString osHref(pszHref);
716 78 : const char* pszDup100 = strstr(pszHref, "1.0.0/1.0.0/");
717 78 : if (pszDup100)
718 : {
719 78 : osHref.resize(pszDup100 - pszHref);
720 78 : osHref += pszDup100 + strlen("1.0.0/");
721 : }
722 78 : poDS->AddSubDataset(osHref, pszTitle);
723 : }
724 : }
725 : }
726 :
727 2 : return poDS;
728 : }
729 :
|