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 3 : GDALWMSMetaDataset::GDALWMSMetaDataset() : papszSubDatasets(NULL)
39 : {
40 3 : }
41 :
42 : /************************************************************************/
43 : /* ~GDALWMSMetaDataset() */
44 : /************************************************************************/
45 :
46 3 : GDALWMSMetaDataset::~GDALWMSMetaDataset()
47 : {
48 3 : CSLDestroy(papszSubDatasets);
49 3 : }
50 :
51 : /************************************************************************/
52 : /* AddSubDataset() */
53 : /************************************************************************/
54 :
55 123 : void GDALWMSMetaDataset::AddSubDataset(const char* pszName,
56 : const char* pszDesc)
57 : {
58 : char szName[80];
59 123 : int nCount = CSLCount(papszSubDatasets ) / 2;
60 :
61 123 : sprintf( szName, "SUBDATASET_%d_NAME", nCount+1 );
62 : papszSubDatasets =
63 123 : CSLSetNameValue( papszSubDatasets, szName, pszName );
64 :
65 123 : sprintf( szName, "SUBDATASET_%d_DESC", nCount+1 );
66 : papszSubDatasets =
67 123 : CSLSetNameValue( papszSubDatasets, szName, pszDesc);
68 123 : }
69 :
70 : /************************************************************************/
71 : /* DownloadGetCapabilities() */
72 : /************************************************************************/
73 :
74 1 : GDALDataset *GDALWMSMetaDataset::DownloadGetCapabilities(GDALOpenInfo *poOpenInfo)
75 : {
76 1 : const char* pszURL = poOpenInfo->pszFilename;
77 1 : if (EQUALN(pszURL, "WMS:", 4))
78 1 : pszURL += 4;
79 :
80 1 : CPLString osFormat = CPLURLGetValue(pszURL, "FORMAT");
81 1 : CPLString osTransparent = CPLURLGetValue(pszURL, "TRANSPARENT");
82 1 : CPLString osVersion = CPLURLGetValue(pszURL, "VERSION");
83 :
84 1 : if (osVersion.size() == 0)
85 1 : osVersion = "1.1.1";
86 :
87 1 : CPLString osURL(pszURL);
88 1 : osURL = CPLURLAddKVP(osURL, "SERVICE", "WMS");
89 1 : osURL = CPLURLAddKVP(osURL, "VERSION", osVersion);
90 1 : osURL = CPLURLAddKVP(osURL, "REQUEST", "GetCapabilities");
91 : /* Remove all other keywords */
92 1 : osURL = CPLURLAddKVP(osURL, "LAYERS", NULL);
93 1 : osURL = CPLURLAddKVP(osURL, "SRS", NULL);
94 1 : osURL = CPLURLAddKVP(osURL, "CRS", NULL);
95 1 : osURL = CPLURLAddKVP(osURL, "BBOX", NULL);
96 1 : osURL = CPLURLAddKVP(osURL, "FORMAT", NULL);
97 1 : osURL = CPLURLAddKVP(osURL, "TRANSPARENT", NULL);
98 1 : osURL = CPLURLAddKVP(osURL, "STYLES", NULL);
99 1 : osURL = CPLURLAddKVP(osURL, "WIDTH", NULL);
100 1 : osURL = CPLURLAddKVP(osURL, "HEIGHT", NULL);
101 :
102 1 : CPLHTTPResult* psResult = CPLHTTPFetch( osURL, NULL );
103 1 : if (psResult == NULL)
104 : {
105 0 : return NULL;
106 : }
107 1 : 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 0 : psResult->nStatus);
113 0 : CPLHTTPDestroyResult(psResult);
114 0 : return NULL;
115 : }
116 1 : 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 1 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
125 1 : 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 1 : GDALDataset* poRet = AnalyzeGetCapabilities(psXML, osFormat, osTransparent);
134 :
135 1 : CPLHTTPDestroyResult(psResult);
136 1 : CPLDestroyXMLNode( psXML );
137 :
138 1 : return poRet;
139 : }
140 :
141 :
142 : /************************************************************************/
143 : /* DownloadGetTileService() */
144 : /************************************************************************/
145 :
146 1 : GDALDataset *GDALWMSMetaDataset::DownloadGetTileService(GDALOpenInfo *poOpenInfo)
147 : {
148 1 : const char* pszURL = poOpenInfo->pszFilename;
149 1 : if (EQUALN(pszURL, "WMS:", 4))
150 1 : pszURL += 4;
151 :
152 1 : CPLString osURL(pszURL);
153 1 : osURL = CPLURLAddKVP(osURL, "SERVICE", "WMS");
154 1 : osURL = CPLURLAddKVP(osURL, "REQUEST", "GetTileService");
155 : /* Remove all other keywords */
156 1 : osURL = CPLURLAddKVP(osURL, "VERSION", NULL);
157 1 : osURL = CPLURLAddKVP(osURL, "LAYERS", NULL);
158 1 : osURL = CPLURLAddKVP(osURL, "SRS", NULL);
159 1 : osURL = CPLURLAddKVP(osURL, "CRS", NULL);
160 1 : osURL = CPLURLAddKVP(osURL, "BBOX", NULL);
161 1 : osURL = CPLURLAddKVP(osURL, "FORMAT", NULL);
162 1 : osURL = CPLURLAddKVP(osURL, "TRANSPARENT", NULL);
163 1 : osURL = CPLURLAddKVP(osURL, "STYLES", NULL);
164 1 : osURL = CPLURLAddKVP(osURL, "WIDTH", NULL);
165 1 : osURL = CPLURLAddKVP(osURL, "HEIGHT", NULL);
166 :
167 1 : CPLHTTPResult* psResult = CPLHTTPFetch( osURL, NULL );
168 1 : if (psResult == NULL)
169 : {
170 0 : return NULL;
171 : }
172 1 : 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 1 : 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 1 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
190 1 : 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 1 : GDALDataset* poRet = AnalyzeGetTileService(psXML);
199 :
200 1 : CPLHTTPDestroyResult(psResult);
201 1 : CPLDestroyXMLNode( psXML );
202 :
203 1 : return poRet;
204 : }
205 : /************************************************************************/
206 : /* GetMetadata() */
207 : /************************************************************************/
208 :
209 3 : char **GDALWMSMetaDataset::GetMetadata( const char *pszDomain )
210 :
211 : {
212 3 : if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
213 3 : 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 31 : void GDALWMSMetaDataset::AddWMSCSubDataset(WMSCTileSetDesc& oWMSCTileSetDesc,
289 : const char* pszTitle,
290 : CPLString osTransparent)
291 : {
292 31 : CPLString osSubdatasetName = "WMS:";
293 31 : osSubdatasetName += osGetURL;
294 31 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SERVICE", "WMS");
295 31 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "VERSION", osVersion);
296 31 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "REQUEST", "GetMap");
297 31 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "LAYERS", oWMSCTileSetDesc.osLayers);
298 31 : if(VersionStringToInt(osVersion.c_str())>= VersionStringToInt("1.3.0"))
299 0 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "CRS", oWMSCTileSetDesc.osSRS);
300 : else
301 31 : 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 31 : oWMSCTileSetDesc.osMaxY.c_str()));
307 :
308 31 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "FORMAT", oWMSCTileSetDesc.osFormat);
309 31 : if (osTransparent.size() != 0)
310 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TRANSPARENT",
311 0 : osTransparent);
312 31 : 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 31 : CPLSPrintf("%d", oWMSCTileSetDesc.nTileWidth));
317 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "OVERVIEWCOUNT",
318 31 : CPLSPrintf("%d", oWMSCTileSetDesc.nResolutions - 1));
319 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "MINRESOLUTION",
320 31 : CPLSPrintf("%.16f", oWMSCTileSetDesc.dfMinResolution));
321 31 : osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "TILED", "true");
322 :
323 31 : if (pszTitle)
324 : {
325 31 : 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 31 : AddSubDataset(osSubdatasetName, pszTitle);
340 : }
341 : }
342 : else
343 : {
344 0 : AddSubDataset(osSubdatasetName, oWMSCTileSetDesc.osLayers);
345 31 : }
346 31 : }
347 :
348 : /************************************************************************/
349 : /* ExploreLayer() */
350 : /************************************************************************/
351 :
352 32 : 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 32 : const char* pszName = CPLGetXMLValue(psXML, "Name", NULL);
362 32 : const char* pszTitle = CPLGetXMLValue(psXML, "Title", NULL);
363 32 : const char* pszAbstract = CPLGetXMLValue(psXML, "Abstract", NULL);
364 :
365 32 : const char* pszSRSLocal = NULL;
366 32 : const char* pszMinXLocal = NULL;
367 32 : const char* pszMinYLocal = NULL;
368 32 : const char* pszMaxXLocal = NULL;
369 32 : const char* pszMaxYLocal = NULL;
370 :
371 : const char* pszSRSTagName =
372 32 : 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 32 : CPLXMLNode* psSRS = CPLGetXMLNode( psXML, "BoundingBox" );
378 32 : if (psSRS == NULL)
379 : {
380 1 : psSRS = CPLGetXMLNode( psXML, "LatLonBoundingBox" );
381 1 : pszSRSLocal = CPLGetXMLValue(psXML, pszSRSTagName, NULL);
382 1 : if (pszSRSLocal == NULL)
383 1 : pszSRSLocal = "EPSG:4326";
384 : }
385 : else
386 31 : pszSRSLocal = CPLGetXMLValue(psSRS, pszSRSTagName, NULL);
387 :
388 32 : if (pszSRSLocal != NULL && psSRS != NULL)
389 : {
390 32 : pszMinXLocal = CPLGetXMLValue(psSRS, "minx", NULL);
391 32 : pszMinYLocal = CPLGetXMLValue(psSRS, "miny", NULL);
392 32 : pszMaxXLocal = CPLGetXMLValue(psSRS, "maxx", NULL);
393 32 : pszMaxYLocal = CPLGetXMLValue(psSRS, "maxy", NULL);
394 :
395 32 : if (pszMinXLocal && pszMinYLocal && pszMaxXLocal && pszMaxYLocal)
396 : {
397 32 : pszSRS = pszSRSLocal;
398 32 : pszMinX = pszMinXLocal;
399 32 : pszMinY = pszMinYLocal;
400 32 : pszMaxX = pszMaxXLocal;
401 32 : pszMaxY = pszMaxYLocal;
402 : }
403 : }
404 :
405 32 : if (pszName != NULL && pszSRS && pszMinX && pszMinY && pszMaxX && pszMaxY)
406 : {
407 31 : CPLString osLocalTransparent(osTransparent);
408 31 : if (osLocalTransparent.size() == 0)
409 : {
410 31 : const char* pszOpaque = CPLGetXMLValue(psXML, "opaque", "0");
411 31 : if (EQUAL(pszOpaque, "1"))
412 0 : osLocalTransparent = "FALSE";
413 : }
414 :
415 31 : WMSCKeyType oWMSCKey(pszName, pszSRS);
416 31 : std::map<WMSCKeyType, WMSCTileSetDesc>::iterator oIter = osMapWMSCTileSet.find(oWMSCKey);
417 31 : if (oIter != osMapWMSCTileSet.end())
418 : {
419 31 : 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 31 : }
427 : }
428 :
429 32 : CPLXMLNode* psIter = psXML->psChild;
430 345 : for(; psIter != NULL; psIter = psIter->psNext)
431 : {
432 313 : if (psIter->eType == CXT_Element)
433 : {
434 282 : if (EQUAL(psIter->pszValue, "Layer"))
435 : ExploreLayer(psIter, osFormat, osTransparent,
436 31 : pszSRS, pszMinX, pszMinY, pszMaxX, pszMaxY);
437 : }
438 : }
439 32 : }
440 :
441 : /************************************************************************/
442 : /* ParseWMSCTileSets() */
443 : /************************************************************************/
444 :
445 1 : void GDALWMSMetaDataset::ParseWMSCTileSets(CPLXMLNode* psXML)
446 : {
447 1 : CPLXMLNode* psIter = psXML->psChild;
448 145 : for(;psIter;psIter = psIter->psNext)
449 : {
450 144 : if (psIter->eType == CXT_Element && EQUAL(psIter->pszValue, "TileSet"))
451 : {
452 144 : const char* pszSRS = CPLGetXMLValue(psIter, "SRS", NULL);
453 144 : if (pszSRS == NULL)
454 0 : continue;
455 :
456 144 : CPLXMLNode* psBoundingBox = CPLGetXMLNode( psIter, "BoundingBox" );
457 144 : if (psBoundingBox == NULL)
458 0 : continue;
459 :
460 144 : const char* pszMinX = CPLGetXMLValue(psBoundingBox, "minx", NULL);
461 144 : const char* pszMinY = CPLGetXMLValue(psBoundingBox, "miny", NULL);
462 144 : const char* pszMaxX = CPLGetXMLValue(psBoundingBox, "maxx", NULL);
463 144 : const char* pszMaxY = CPLGetXMLValue(psBoundingBox, "maxy", NULL);
464 144 : if (pszMinX == NULL || pszMinY == NULL || pszMaxX == NULL || pszMaxY == NULL)
465 0 : continue;
466 :
467 144 : double dfMinX = CPLAtofM(pszMinX);
468 144 : double dfMinY = CPLAtofM(pszMinY);
469 144 : double dfMaxX = CPLAtofM(pszMaxX);
470 144 : double dfMaxY = CPLAtofM(pszMaxY);
471 144 : if (dfMaxY <= dfMinY || dfMaxX <= dfMinX)
472 0 : continue;
473 :
474 144 : const char* pszFormat = CPLGetXMLValue( psIter, "Format", NULL );
475 144 : if (pszFormat == NULL)
476 0 : continue;
477 144 : if (strstr(pszFormat, "kml"))
478 0 : continue;
479 :
480 144 : const char* pszTileWidth = CPLGetXMLValue(psIter, "Width", NULL);
481 144 : const char* pszTileHeight = CPLGetXMLValue(psIter, "Height", NULL);
482 144 : if (pszTileWidth == NULL || pszTileHeight == NULL)
483 0 : continue;
484 :
485 144 : int nTileWidth = atoi(pszTileWidth);
486 144 : int nTileHeight = atoi(pszTileHeight);
487 144 : if (nTileWidth < 128 || nTileHeight < 128)
488 0 : continue;
489 :
490 144 : const char* pszLayers = CPLGetXMLValue(psIter, "Layers", NULL);
491 144 : if (pszLayers == NULL)
492 0 : continue;
493 :
494 144 : const char* pszResolutions = CPLGetXMLValue(psIter, "Resolutions", NULL);
495 144 : if (pszResolutions == NULL)
496 0 : continue;
497 144 : char** papszTokens = CSLTokenizeStringComplex(pszResolutions, " ", 0, 0);
498 144 : double dfMinResolution = 0;
499 : int i;
500 3960 : for(i=0; papszTokens && papszTokens[i]; i++)
501 : {
502 3816 : double dfResolution = CPLAtofM(papszTokens[i]);
503 3816 : if (i==0 || dfResolution < dfMinResolution)
504 3816 : dfMinResolution = dfResolution;
505 : }
506 144 : CSLDestroy(papszTokens);
507 144 : int nResolutions = i;
508 144 : if (nResolutions == 0)
509 0 : continue;
510 :
511 144 : 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 144 : WMSCKeyType oWMSCKey(pszLayers, pszSRS);
517 144 : std::map<WMSCKeyType, WMSCTileSetDesc>::iterator oIter = osMapWMSCTileSet.find(oWMSCKey);
518 144 : if (oIter != osMapWMSCTileSet.end())
519 82 : continue;
520 :
521 62 : WMSCTileSetDesc oWMSCTileSet;
522 62 : oWMSCTileSet.osLayers = pszLayers;
523 62 : oWMSCTileSet.osSRS = pszSRS;
524 62 : oWMSCTileSet.osMinX = pszMinX;
525 62 : oWMSCTileSet.osMinY = pszMinY;
526 62 : oWMSCTileSet.osMaxX = pszMaxX;
527 62 : oWMSCTileSet.osMaxY = pszMaxY;
528 62 : oWMSCTileSet.dfMinX = dfMinX;
529 62 : oWMSCTileSet.dfMinY = dfMinY;
530 62 : oWMSCTileSet.dfMaxX = dfMaxX;
531 62 : oWMSCTileSet.dfMaxY = dfMaxY;
532 62 : oWMSCTileSet.nResolutions = nResolutions;
533 62 : oWMSCTileSet.dfMinResolution = dfMinResolution;
534 62 : oWMSCTileSet.osFormat = pszFormat;
535 62 : oWMSCTileSet.osStyle = pszStyles;
536 62 : oWMSCTileSet.nTileWidth = nTileWidth;
537 62 : oWMSCTileSet.nTileHeight = nTileHeight;
538 :
539 62 : osMapWMSCTileSet[oWMSCKey] = oWMSCTileSet;
540 : }
541 : }
542 1 : }
543 :
544 : /************************************************************************/
545 : /* AnalyzeGetCapabilities() */
546 : /************************************************************************/
547 :
548 1 : GDALDataset* GDALWMSMetaDataset::AnalyzeGetCapabilities(CPLXMLNode* psXML,
549 : CPLString osFormat,
550 : CPLString osTransparent)
551 : {
552 1 : const char* pszEncoding = NULL;
553 1 : if (psXML->eType == CXT_Element && strcmp(psXML->pszValue, "?xml") == 0)
554 1 : pszEncoding = CPLGetXMLValue(psXML, "encoding", NULL);
555 :
556 1 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=WMT_MS_Capabilities" );
557 1 : if (psRoot == NULL)
558 0 : psRoot = CPLGetXMLNode( psXML, "=WMS_Capabilities" );
559 1 : if (psRoot == NULL)
560 0 : return NULL;
561 1 : CPLXMLNode* psCapability = CPLGetXMLNode(psRoot, "Capability");
562 1 : if (psCapability == NULL)
563 0 : return NULL;
564 :
565 : CPLXMLNode* psOnlineResource = CPLGetXMLNode(psCapability,
566 1 : "Request.GetMap.DCPType.HTTP.Get.OnlineResource");
567 1 : if (psOnlineResource == NULL)
568 0 : return NULL;
569 : const char* pszGetURL =
570 1 : CPLGetXMLValue(psOnlineResource, "xlink:href", NULL);
571 1 : if (pszGetURL == NULL)
572 0 : return NULL;
573 :
574 1 : CPLXMLNode* psLayer = CPLGetXMLNode(psCapability, "Layer");
575 1 : if (psLayer == NULL)
576 0 : return NULL;
577 :
578 : CPLXMLNode* psVendorSpecificCapabilities =
579 1 : CPLGetXMLNode(psCapability, "VendorSpecificCapabilities");
580 :
581 1 : GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset();
582 1 : const char* pszVersion = CPLGetXMLValue(psRoot, "version", NULL);
583 1 : if (pszVersion)
584 1 : poDS->osVersion = pszVersion;
585 : else
586 0 : poDS->osVersion = "1.1.1";
587 1 : poDS->osGetURL = pszGetURL;
588 2 : poDS->osXMLEncoding = pszEncoding ? pszEncoding : "";
589 1 : if (psVendorSpecificCapabilities)
590 1 : poDS->ParseWMSCTileSets(psVendorSpecificCapabilities);
591 1 : poDS->ExploreLayer(psLayer, osFormat, osTransparent);
592 :
593 1 : return poDS;
594 : }
595 :
596 : /************************************************************************/
597 : /* AddTiledSubDataset() */
598 : /************************************************************************/
599 :
600 53 : void GDALWMSMetaDataset::AddTiledSubDataset(const char* pszTiledGroupName,
601 : const char* pszTitle)
602 : {
603 53 : CPLString osSubdatasetName = "<GDAL_WMS><Service name=\"TiledWMS\"><ServerUrl>";
604 53 : osSubdatasetName += osGetURL;
605 53 : osSubdatasetName += "</ServerUrl><TiledGroupName>";
606 53 : osSubdatasetName += pszTiledGroupName;
607 53 : osSubdatasetName += "</TiledGroupName></Service></GDAL_WMS>";
608 :
609 53 : if (pszTitle)
610 : {
611 53 : 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 53 : AddSubDataset(osSubdatasetName, pszTitle);
626 : }
627 : }
628 : else
629 : {
630 0 : AddSubDataset(osSubdatasetName, pszTiledGroupName);
631 53 : }
632 53 : }
633 :
634 : /************************************************************************/
635 : /* AnalyzeGetTileServiceRecurse() */
636 : /************************************************************************/
637 :
638 5 : void GDALWMSMetaDataset::AnalyzeGetTileServiceRecurse(CPLXMLNode* psXML)
639 : {
640 5 : CPLXMLNode* psIter = psXML->psChild;
641 76 : for(; psIter != NULL; psIter = psIter->psNext)
642 : {
643 124 : if (psIter->eType == CXT_Element &&
644 : EQUAL(psIter->pszValue, "TiledGroup"))
645 : {
646 53 : const char* pszName = CPLGetXMLValue(psIter, "Name", NULL);
647 53 : const char* pszTitle = CPLGetXMLValue(psIter, "Title", NULL);
648 53 : if (pszName)
649 53 : AddTiledSubDataset(pszName, pszTitle);
650 : }
651 18 : else if (psIter->eType == CXT_Element &&
652 : EQUAL(psIter->pszValue, "TiledGroups"))
653 : {
654 4 : AnalyzeGetTileServiceRecurse(psIter);
655 : }
656 : }
657 5 : }
658 :
659 : /************************************************************************/
660 : /* AnalyzeGetTileService() */
661 : /************************************************************************/
662 :
663 1 : GDALDataset* GDALWMSMetaDataset::AnalyzeGetTileService(CPLXMLNode* psXML)
664 : {
665 1 : const char* pszEncoding = NULL;
666 1 : if (psXML->eType == CXT_Element && strcmp(psXML->pszValue, "?xml") == 0)
667 0 : pszEncoding = CPLGetXMLValue(psXML, "encoding", NULL);
668 :
669 1 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=WMS_Tile_Service" );
670 1 : if (psRoot == NULL)
671 0 : return NULL;
672 1 : CPLXMLNode* psTiledPatterns = CPLGetXMLNode(psRoot, "TiledPatterns");
673 1 : if (psTiledPatterns == NULL)
674 0 : return NULL;
675 :
676 : const char* pszURL = CPLGetXMLValue(psTiledPatterns,
677 1 : "OnlineResource.xlink:href", NULL);
678 1 : if (pszURL == NULL)
679 0 : return NULL;
680 :
681 1 : GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset();
682 2 : poDS->osGetURL = pszURL;
683 1 : poDS->osXMLEncoding = pszEncoding ? pszEncoding : "";
684 :
685 1 : poDS->AnalyzeGetTileServiceRecurse(psTiledPatterns);
686 :
687 1 : return poDS;
688 : }
689 :
690 : /************************************************************************/
691 : /* AnalyzeTileMapService() */
692 : /************************************************************************/
693 :
694 1 : GDALDataset* GDALWMSMetaDataset::AnalyzeTileMapService(CPLXMLNode* psXML)
695 : {
696 1 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TileMapService" );
697 1 : if (psRoot == NULL)
698 0 : return NULL;
699 1 : CPLXMLNode* psTileMaps = CPLGetXMLNode(psRoot, "TileMaps");
700 1 : if (psTileMaps == NULL)
701 0 : return NULL;
702 :
703 1 : GDALWMSMetaDataset* poDS = new GDALWMSMetaDataset();
704 :
705 1 : CPLXMLNode* psIter = psTileMaps->psChild;
706 40 : for(; psIter != NULL; psIter = psIter->psNext)
707 : {
708 39 : if (psIter->eType == CXT_Element &&
709 : EQUAL(psIter->pszValue, "TileMap"))
710 : {
711 39 : const char* pszHref = CPLGetXMLValue(psIter, "href", NULL);
712 39 : const char* pszTitle = CPLGetXMLValue(psIter, "title", NULL);
713 39 : if (pszHref && pszTitle)
714 : {
715 39 : CPLString osHref(pszHref);
716 39 : const char* pszDup100 = strstr(pszHref, "1.0.0/1.0.0/");
717 39 : if (pszDup100)
718 : {
719 39 : osHref.resize(pszDup100 - pszHref);
720 39 : osHref += pszDup100 + strlen("1.0.0/");
721 : }
722 39 : poDS->AddSubDataset(osHref, pszTitle);
723 : }
724 : }
725 : }
726 :
727 1 : return poDS;
728 : }
729 :
|