LCOV - code coverage report
Current view: directory - frmts/wms - wmsdriver.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 421 232 55.1 %
Date: 2011-12-18 Functions: 8 7 87.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: wmsdriver.cpp 22576 2011-06-24 13:14:21Z warmerdam $
       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                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "stdinc.h"
      32                 : #include "wmsmetadataset.h"
      33                 : 
      34                 : /************************************************************************/
      35                 : /*              GDALWMSDatasetGetConfigFromURL()                        */
      36                 : /************************************************************************/
      37                 : 
      38                 : static
      39               2 : CPLXMLNode * GDALWMSDatasetGetConfigFromURL(GDALOpenInfo *poOpenInfo)
      40                 : {
      41               2 :     const char* pszBaseURL = poOpenInfo->pszFilename;
      42               2 :     if (EQUALN(pszBaseURL, "WMS:", 4))
      43               2 :         pszBaseURL += 4;
      44                 : 
      45               2 :     CPLString osLayer = CPLURLGetValue(pszBaseURL, "LAYERS");
      46               2 :     CPLString osVersion = CPLURLGetValue(pszBaseURL, "VERSION");
      47               2 :     CPLString osSRS = CPLURLGetValue(pszBaseURL, "SRS");
      48               2 :     CPLString osCRS = CPLURLGetValue(pszBaseURL, "CRS");
      49               2 :     CPLString osBBOX = CPLURLGetValue(pszBaseURL, "BBOX");
      50               2 :     CPLString osFormat = CPLURLGetValue(pszBaseURL, "FORMAT");
      51               2 :     CPLString osTransparent = CPLURLGetValue(pszBaseURL, "TRANSPARENT");
      52                 : 
      53                 :     /* GDAL specific extensions to alter the default settings */
      54               2 :     CPLString osOverviewCount = CPLURLGetValue(pszBaseURL, "OVERVIEWCOUNT");
      55               2 :     CPLString osTileSize = CPLURLGetValue(pszBaseURL, "TILESIZE");
      56               2 :     CPLString osMinResolution = CPLURLGetValue(pszBaseURL, "MINRESOLUTION");
      57               2 :     CPLString osBBOXOrder = CPLURLGetValue(pszBaseURL, "BBOXORDER");
      58                 : 
      59               2 :     CPLString osBaseURL = pszBaseURL;
      60                 :     /* Remove all keywords to get base URL */
      61                 : 
      62               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "VERSION", NULL);
      63               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "REQUEST", NULL);
      64               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "LAYERS", NULL);
      65               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "SRS", NULL);
      66               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "CRS", NULL);
      67               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "BBOX", NULL);
      68               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "FORMAT", NULL);
      69               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "TRANSPARENT", NULL);
      70               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "STYLES", NULL);
      71               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "WIDTH", NULL);
      72               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "HEIGHT", NULL);
      73                 : 
      74               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "OVERVIEWCOUNT", NULL);
      75               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "TILESIZE", NULL);
      76               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "MINRESOLUTION", NULL);
      77               2 :     osBaseURL = CPLURLAddKVP(osBaseURL, "BBOXORDER", NULL);
      78                 : 
      79               2 :     if (osBaseURL.size() > 0 && osBaseURL[osBaseURL.size() - 1] == '&')
      80               1 :         osBaseURL.resize(osBaseURL.size() - 1);
      81                 : 
      82               2 :     if (osVersion.size() == 0)
      83               0 :         osVersion = "1.1.1";
      84                 : 
      85               2 :     CPLString osSRSTag;
      86               2 :     CPLString osSRSValue;
      87               2 :     if(VersionStringToInt(osVersion.c_str())>= VersionStringToInt("1.3.0"))
      88                 :     {
      89               0 :         if (osSRS.size())
      90                 :         {
      91                 :             CPLError(CE_Warning, CPLE_AppDefined,
      92               0 :                      "WMS version 1.3 and above expects CRS however SRS was set instead.");
      93                 :         }
      94               0 :         osSRSValue = osCRS;
      95               0 :         osSRSTag = "CRS";
      96                 :     }
      97                 :     else
      98                 :     {
      99               2 :         if (osCRS.size())
     100                 :         {
     101                 :             CPLError(CE_Warning, CPLE_AppDefined,
     102               0 :                      "WMS version 1.1.1 and below expects SRS however CRS was set instead.");
     103                 :         }
     104               2 :         osSRSValue = osSRS;
     105               2 :         osSRSTag = "SRS";
     106                 :     }
     107                 : 
     108               2 :     if (osSRSValue.size() == 0)
     109               0 :         osSRSValue = "EPSG:4326";
     110                 :     
     111               2 :     if (osBBOX.size() == 0)
     112                 :     {
     113               0 :         if (osBBOXOrder.compare("yxYX") == 0)
     114               0 :             osBBOX = "-90,-180,90,180";
     115                 :         else
     116               0 :             osBBOX = "-180,-90,180,90";
     117                 :     }
     118                 : 
     119               2 :     char** papszTokens = CSLTokenizeStringComplex(osBBOX, ",", 0, 0);
     120               2 :     if (CSLCount(papszTokens) != 4)
     121                 :     {
     122               0 :         CSLDestroy(papszTokens);
     123               0 :         return NULL;
     124                 :     }
     125               2 :     const char* pszMinX = papszTokens[0];
     126               2 :     const char* pszMinY = papszTokens[1];
     127               2 :     const char* pszMaxX = papszTokens[2];
     128               2 :     const char* pszMaxY = papszTokens[3];
     129                 : 
     130               2 :     if (osBBOXOrder.compare("yxYX") == 0)
     131                 :     {
     132               0 :         std::swap(pszMinX, pszMinY);
     133               0 :         std::swap(pszMaxX, pszMaxY);
     134                 :     }
     135                 : 
     136               2 :     double dfMinX = CPLAtofM(pszMinX);
     137               2 :     double dfMinY = CPLAtofM(pszMinY);
     138               2 :     double dfMaxX = CPLAtofM(pszMaxX);
     139               2 :     double dfMaxY = CPLAtofM(pszMaxY);
     140                 : 
     141               2 :     if (dfMaxY <= dfMinY || dfMaxX <= dfMinX)
     142                 :     {
     143               0 :         CSLDestroy(papszTokens);
     144               0 :         return NULL;
     145                 :     }
     146                 : 
     147               2 :     int nTileSize = atoi(osTileSize);
     148               2 :     if (nTileSize <= 128 || nTileSize > 2048)
     149               1 :         nTileSize = 1024;
     150                 : 
     151                 :     int nXSize, nYSize;
     152                 : 
     153               2 :     int nOverviewCount = (osOverviewCount.size()) ? atoi(osOverviewCount) : 20;
     154                 : 
     155               2 :     if (osMinResolution.size() != 0)
     156                 :     {
     157               1 :         double dfMinResolution = CPLAtofM(osMinResolution);
     158                 : 
     159               7 :         while (nOverviewCount > 20)
     160                 :         {
     161               5 :             nOverviewCount --;
     162               5 :             dfMinResolution *= 2;
     163                 :         }
     164                 : 
     165               1 :         nXSize = (int) ((dfMaxX - dfMinX) / dfMinResolution + 0.5);
     166               1 :         nYSize = (int) ((dfMaxY - dfMinY) / dfMinResolution + 0.5);
     167                 :     }
     168                 :     else
     169                 :     {
     170               1 :         double dfRatio = (dfMaxX - dfMinX) / (dfMaxY - dfMinY);
     171               1 :         if (dfRatio > 1)
     172                 :         {
     173               1 :             nXSize = nTileSize;
     174               1 :             nYSize = (int) (nXSize / dfRatio);
     175                 :         }
     176                 :         else
     177                 :         {
     178               0 :             nYSize = nTileSize;
     179               0 :             nXSize = (int) (nYSize * dfRatio);
     180                 :         }
     181                 : 
     182               1 :         if (nOverviewCount < 0 || nOverviewCount > 20)
     183               0 :             nOverviewCount = 20;
     184                 : 
     185               1 :         nXSize = nXSize * (1 << nOverviewCount);
     186               1 :         nYSize = nYSize * (1 << nOverviewCount);
     187                 :     }
     188                 : 
     189               2 :     int bTransparent = osTransparent.size() ? CSLTestBoolean(osTransparent) : FALSE;
     190                 : 
     191               2 :     if (osFormat.size() == 0)
     192                 :     {
     193               1 :         if (!bTransparent)
     194                 :         {
     195               1 :             osFormat = "image/jpeg";
     196                 :         }
     197                 :         else
     198                 :         {
     199               0 :             osFormat = "image/png";
     200                 :         }
     201                 :     }
     202                 : 
     203               2 :     char* pszEscapedURL = CPLEscapeString(osBaseURL.c_str(), -1, CPLES_XML);
     204               2 :     char* pszEscapedLayerURL = CPLEscapeString(osLayer.c_str(), -1, CPLES_URL);
     205               2 :     char* pszEscapedLayerXML = CPLEscapeString(pszEscapedLayerURL, -1, CPLES_XML);
     206                 : 
     207                 :     CPLString osXML = CPLSPrintf(
     208                 :             "<GDAL_WMS>\n"
     209                 :             "  <Service name=\"WMS\">\n"
     210                 :             "    <Version>%s</Version>\n"
     211                 :             "    <ServerUrl>%s</ServerUrl>\n"
     212                 :             "    <Layers>%s</Layers>\n"
     213                 :             "    <%s>%s</%s>\n"
     214                 :             "    <ImageFormat>%s</ImageFormat>\n"
     215                 :             "    <Transparent>%s</Transparent>\n"
     216                 :             "    <BBoxOrder>%s</BBoxOrder>\n"
     217                 :             "  </Service>\n"
     218                 :             "  <DataWindow>\n"
     219                 :             "    <UpperLeftX>%s</UpperLeftX>\n"
     220                 :             "    <UpperLeftY>%s</UpperLeftY>\n"
     221                 :             "    <LowerRightX>%s</LowerRightX>\n"
     222                 :             "    <LowerRightY>%s</LowerRightY>\n"
     223                 :             "    <SizeX>%d</SizeX>\n"
     224                 :             "    <SizeY>%d</SizeY>\n"
     225                 :             "  </DataWindow>\n"
     226                 :             "  <BandsCount>%d</BandsCount>\n"
     227                 :             "  <BlockSizeX>%d</BlockSizeX>\n"
     228                 :             "  <BlockSizeY>%d</BlockSizeY>\n"
     229                 :             "  <OverviewCount>%d</OverviewCount>\n"
     230                 :             "</GDAL_WMS>\n",
     231                 :             osVersion.c_str(),
     232                 :             pszEscapedURL,
     233                 :             pszEscapedLayerXML,
     234                 :             osSRSTag.c_str(),
     235                 :             osSRSValue.c_str(),
     236                 :             osSRSTag.c_str(),
     237                 :             osFormat.c_str(),
     238                 :             (bTransparent) ? "TRUE" : "FALSE",
     239                 :             (osBBOXOrder.size()) ? osBBOXOrder.c_str() : "xyXY",
     240                 :             pszMinX, pszMaxY, pszMaxX, pszMinY,
     241                 :             nXSize, nYSize,
     242                 :             (bTransparent) ? 4 : 3,
     243                 :             nTileSize, nTileSize,
     244               2 :             nOverviewCount);
     245                 : 
     246               2 :     CPLFree(pszEscapedURL);
     247               2 :     CPLFree(pszEscapedLayerURL);
     248               2 :     CPLFree(pszEscapedLayerXML);
     249                 : 
     250               2 :     CSLDestroy(papszTokens);
     251                 : 
     252               2 :     CPLDebug("WMS", "Opening WMS :\n%s", osXML.c_str());
     253                 : 
     254               2 :     return CPLParseXMLString(osXML);
     255                 : }
     256                 : 
     257                 : /************************************************************************/
     258                 : /*              GDALWMSDatasetGetConfigFromTileMap()                    */
     259                 : /************************************************************************/
     260                 : 
     261                 : static
     262               0 : CPLXMLNode * GDALWMSDatasetGetConfigFromTileMap(CPLXMLNode* psXML)
     263                 : {
     264               0 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TileMap" );
     265               0 :     if (psRoot == NULL)
     266               0 :         return NULL;
     267                 : 
     268               0 :     CPLXMLNode* psTileSets = CPLGetXMLNode(psRoot, "TileSets");
     269               0 :     if (psTileSets == NULL)
     270               0 :         return NULL;
     271                 : 
     272               0 :     const char* pszURL = CPLGetXMLValue(psRoot, "tilemapservice", NULL);
     273                 : 
     274               0 :     int bCanChangeURL = TRUE;
     275                 : 
     276               0 :     CPLString osURL;
     277               0 :     if (pszURL)
     278                 :     {
     279               0 :         osURL = pszURL;
     280                 :         /* Special hack for http://tilecache.osgeo.org/wms-c/Basic.py/1.0.0/basic/ */
     281               0 :         if (strlen(pszURL) > 10 &&
     282                 :             strncmp(pszURL, "http://tilecache.osgeo.org/wms-c/Basic.py/1.0.0/",
     283                 :                             strlen("http://tilecache.osgeo.org/wms-c/Basic.py/1.0.0/")) == 0 &&
     284                 :             strcmp(pszURL + strlen(pszURL) - strlen("1.0.0/"), "1.0.0/") == 0)
     285                 :         {
     286               0 :             osURL.resize(strlen(pszURL) - strlen("1.0.0/"));
     287               0 :             bCanChangeURL = FALSE;
     288                 :         }
     289               0 :         osURL += "${z}/${x}/${y}.${format}";
     290                 :     }
     291                 : 
     292               0 :     const char* pszSRS = CPLGetXMLValue(psRoot, "SRS", NULL);
     293               0 :     if (pszSRS == NULL)
     294               0 :         return NULL;
     295                 : 
     296               0 :     CPLXMLNode* psBoundingBox = CPLGetXMLNode( psRoot, "BoundingBox" );
     297               0 :     if (psBoundingBox == NULL)
     298               0 :         return NULL;
     299                 : 
     300               0 :     const char* pszMinX = CPLGetXMLValue(psBoundingBox, "minx", NULL);
     301               0 :     const char* pszMinY = CPLGetXMLValue(psBoundingBox, "miny", NULL);
     302               0 :     const char* pszMaxX = CPLGetXMLValue(psBoundingBox, "maxx", NULL);
     303               0 :     const char* pszMaxY = CPLGetXMLValue(psBoundingBox, "maxy", NULL);
     304               0 :     if (pszMinX == NULL || pszMinY == NULL || pszMaxX == NULL || pszMaxY == NULL)
     305               0 :         return NULL;
     306                 : 
     307               0 :     double dfMinX = CPLAtofM(pszMinX);
     308               0 :     double dfMinY = CPLAtofM(pszMinY);
     309               0 :     double dfMaxX = CPLAtofM(pszMaxX);
     310               0 :     double dfMaxY = CPLAtofM(pszMaxY);
     311               0 :     if (dfMaxY <= dfMinY || dfMaxX <= dfMinX)
     312               0 :         return NULL;
     313                 : 
     314               0 :     CPLXMLNode* psTileFormat = CPLGetXMLNode( psRoot, "TileFormat" );
     315               0 :     if (psTileFormat == NULL)
     316               0 :         return NULL;
     317                 : 
     318               0 :     const char* pszTileWidth = CPLGetXMLValue(psTileFormat, "width", NULL);
     319               0 :     const char* pszTileHeight = CPLGetXMLValue(psTileFormat, "height", NULL);
     320               0 :     const char* pszTileFormat = CPLGetXMLValue(psTileFormat, "extension", NULL);
     321               0 :     if (pszTileWidth == NULL || pszTileHeight == NULL || pszTileFormat == NULL)
     322               0 :         return NULL;
     323                 : 
     324               0 :     int nTileWidth = atoi(pszTileWidth);
     325               0 :     int nTileHeight = atoi(pszTileHeight);
     326               0 :     if (nTileWidth < 128 || nTileHeight < 128)
     327               0 :         return NULL;
     328                 : 
     329               0 :     CPLXMLNode* psIter = psTileSets->psChild;
     330               0 :     int nLevelCount = 0;
     331               0 :     double dfPixelSize = 0;
     332               0 :     for(; psIter != NULL; psIter = psIter->psNext)
     333                 :     {
     334               0 :         if (psIter->eType == CXT_Element &&
     335                 :             EQUAL(psIter->pszValue, "TileSet"))
     336                 :         {
     337                 :             const char* pszOrder =
     338               0 :                 CPLGetXMLValue(psIter, "order", NULL);
     339               0 :             if (pszOrder == NULL)
     340                 :             {
     341               0 :                 CPLDebug("WMS", "Cannot find order attribute");
     342               0 :                 return NULL;
     343                 :             }
     344               0 :             if (atoi(pszOrder) != nLevelCount)
     345                 :             {
     346               0 :                 CPLDebug("WMS", "Expected order=%d, got %s", nLevelCount, pszOrder);
     347               0 :                 return NULL;
     348                 :             }
     349                 : 
     350                 :             const char* pszHref =
     351               0 :                 CPLGetXMLValue(psIter, "href", NULL);
     352               0 :             if (nLevelCount == 0 && pszHref != NULL)
     353                 :             {
     354               0 :                 if (bCanChangeURL && strlen(pszHref) > 10 &&
     355                 :                     strcmp(pszHref + strlen(pszHref) - strlen("/0"), "/0") == 0)
     356                 :                 {
     357               0 :                     osURL = pszHref;
     358               0 :                     osURL.resize(strlen(pszHref) - strlen("/0"));
     359               0 :                     osURL += "/${z}/${x}/${y}.${format}";
     360                 :                 }
     361                 :             }
     362                 :             const char* pszUnitsPerPixel =
     363               0 :                 CPLGetXMLValue(psIter, "units-per-pixel", NULL);
     364               0 :             if (pszUnitsPerPixel == NULL)
     365               0 :                 return NULL;
     366               0 :             dfPixelSize = CPLAtofM(pszUnitsPerPixel);
     367                 : 
     368               0 :             nLevelCount++;
     369                 :         }
     370                 :     }
     371                 : 
     372               0 :     if (nLevelCount == 0 || osURL.size() == 0)
     373               0 :         return NULL;
     374                 : 
     375               0 :     int nXSize = 0;
     376               0 :     int nYSize = 0;
     377                 : 
     378               0 :     while(nLevelCount > 0)
     379                 :     {
     380               0 :         GIntBig nXSizeBig = (GIntBig)((dfMaxX - dfMinX) / dfPixelSize + 0.5);
     381               0 :         GIntBig nYSizeBig = (GIntBig)((dfMaxY - dfMinY) / dfPixelSize + 0.5);
     382               0 :         if (nXSizeBig < INT_MAX && nYSizeBig < INT_MAX)
     383                 :         {
     384               0 :             nXSize = (int)nXSizeBig;
     385               0 :             nYSize = (int)nYSizeBig;
     386               0 :             break;
     387                 :         }
     388               0 :         CPLDebug("WMS", "Dropping one overview level so raster size fits into 32bit...");
     389               0 :         dfPixelSize *= 2;
     390               0 :         nLevelCount --;
     391                 :     }
     392                 : 
     393               0 :     char* pszEscapedURL = CPLEscapeString(osURL.c_str(), -1, CPLES_XML);
     394                 :     
     395                 :     CPLString osXML = CPLSPrintf(
     396                 :             "<GDAL_WMS>\n"
     397                 :             "  <Service name=\"TMS\">\n"
     398                 :             "    <ServerUrl>%s</ServerUrl>\n"
     399                 :             "    <Format>%s</Format>\n"
     400                 :             "  </Service>\n"
     401                 :             "  <DataWindow>\n"
     402                 :             "    <UpperLeftX>%s</UpperLeftX>\n"
     403                 :             "    <UpperLeftY>%s</UpperLeftY>\n"
     404                 :             "    <LowerRightX>%s</LowerRightX>\n"
     405                 :             "    <LowerRightY>%s</LowerRightY>\n"
     406                 :             "    <TileLevel>%d</TileLevel>\n"
     407                 :             "    <SizeX>%d</SizeX>\n"
     408                 :             "    <SizeY>%d</SizeY>\n"
     409                 :             "  </DataWindow>\n"
     410                 :             "  <Projection>%s</Projection>\n"
     411                 :             "  <BlockSizeX>%d</BlockSizeX>\n"
     412                 :             "  <BlockSizeY>%d</BlockSizeY>\n"
     413                 :             "  <BandsCount>%d</BandsCount>\n"
     414                 :             "</GDAL_WMS>\n",
     415                 :             pszEscapedURL,
     416                 :             pszTileFormat,
     417                 :             pszMinX, pszMaxY, pszMaxX, pszMinY,
     418                 :             nLevelCount - 1,
     419                 :             nXSize, nYSize,
     420                 :             pszSRS,
     421               0 :             nTileWidth, nTileHeight, 3);
     422               0 :     CPLDebug("WMS", "Opening TMS :\n%s", osXML.c_str());
     423                 : 
     424               0 :     CPLFree(pszEscapedURL);
     425                 : 
     426               0 :     return CPLParseXMLString(osXML);
     427                 : }
     428                 : 
     429                 : /************************************************************************/
     430                 : /*             GDALWMSDatasetGetConfigFromArcGISJSON()                  */
     431                 : /************************************************************************/
     432                 : 
     433               1 : static CPLXMLNode* GDALWMSDatasetGetConfigFromArcGISJSON(const char* pszURL,
     434                 :                                                          const char* pszContent)
     435                 : {
     436                 :     /* TODO : use JSONC library to parse. But we don't really need it */
     437               1 :     CPLString osTmpFilename(CPLSPrintf("/vsimem/WMSArcGISJSON%p", pszURL));
     438                 :     VSILFILE* fp = VSIFileFromMemBuffer( osTmpFilename,
     439                 :                                          (GByte*)pszContent,
     440                 :                                          strlen(pszContent),
     441               1 :                                          FALSE);
     442                 :     const char* pszLine;
     443               1 :     int nTileWidth = -1, nTileHeight = -1;
     444               1 :     int nWKID = -1;
     445               1 :     double dfMinX = 0, dfMaxY = 0;
     446               1 :     int bHasMinX = FALSE, bHasMaxY = FALSE;
     447               1 :     int nExpectedLevel = 0;
     448               1 :     double dfBaseResolution = 0;
     449             120 :     while((pszLine = CPLReadLine2L(fp, 4096, NULL)) != NULL)
     450                 :     {
     451                 :         const char* pszPtr;
     452             118 :         if ((pszPtr = strstr(pszLine, "\"rows\" : ")) != NULL)
     453               1 :             nTileHeight = atoi(pszPtr + strlen("\"rows\" : "));
     454             117 :         else if ((pszPtr = strstr(pszLine, "\"cols\" : ")) != NULL)
     455               1 :             nTileWidth = atoi(pszPtr + strlen("\"cols\" : "));
     456             116 :         else if ((pszPtr = strstr(pszLine, "\"wkid\" : ")) != NULL)
     457                 :         {
     458               4 :             int nVal = atoi(pszPtr + strlen("\"wkid\" : "));
     459               4 :             if (nWKID < 0)
     460               1 :                 nWKID = nVal;
     461               3 :             else if (nWKID != nVal)
     462                 :             {
     463               0 :                 CPLDebug("WMS", "Inconsisant WKID values : %d, %d", nVal, nWKID);
     464               0 :                 VSIFCloseL(fp);
     465               0 :                 return NULL;
     466                 :             }
     467                 :         }
     468             112 :         else if ((pszPtr = strstr(pszLine, "\"x\" : ")) != NULL)
     469                 :         {
     470               1 :             bHasMinX = TRUE;
     471               1 :             dfMinX = CPLAtofM(pszPtr + strlen("\"x\" : "));
     472                 :         }
     473             111 :         else if ((pszPtr = strstr(pszLine, "\"y\" : ")) != NULL)
     474                 :         {
     475               1 :             bHasMaxY = TRUE;
     476               1 :             dfMaxY = CPLAtofM(pszPtr + strlen("\"y\" : "));
     477                 :         }
     478             110 :         else if ((pszPtr = strstr(pszLine, "\"level\" : ")) != NULL)
     479                 :         {
     480              20 :             int nLevel = atoi(pszPtr + strlen("\"level\" : "));
     481              20 :             if (nLevel != nExpectedLevel)
     482                 :             {
     483               0 :                 CPLDebug("WMS", "Expected level : %d, got : %d", nExpectedLevel, nLevel);
     484               0 :                 VSIFCloseL(fp);
     485               0 :                 return NULL;
     486                 :             }
     487                 : 
     488              20 :             if ((pszPtr = strstr(pszLine, "\"resolution\" : ")) != NULL)
     489                 :             {
     490              20 :                 double dfResolution = CPLAtofM(pszPtr + strlen("\"resolution\" : "));
     491              20 :                 if (nLevel == 0)
     492               1 :                     dfBaseResolution = dfResolution;
     493                 :             }
     494                 :             else
     495                 :             {
     496               0 :                 CPLDebug("WMS", "Did not get resolution");
     497               0 :                 VSIFCloseL(fp);
     498               0 :                 return NULL;
     499                 :             }
     500              20 :             nExpectedLevel ++;
     501                 :         }
     502                 :     }
     503               1 :     VSIFCloseL(fp);
     504                 : 
     505               1 :     int nLevelCount = nExpectedLevel - 1;
     506               1 :     if (nLevelCount < 1)
     507                 :     {
     508               0 :         CPLDebug("WMS", "Did not get levels");
     509               0 :         return NULL;
     510                 :     }
     511                 : 
     512               1 :     if (nTileWidth <= 0)
     513                 :     {
     514               0 :         CPLDebug("WMS", "Did not get tile width");
     515               0 :         return NULL;
     516                 :     }
     517               1 :     if (nTileHeight <= 0)
     518                 :     {
     519               0 :         CPLDebug("WMS", "Did not get tile height");
     520               0 :         return NULL;
     521                 :     }
     522               1 :     if (nWKID <= 0)
     523                 :     {
     524               0 :         CPLDebug("WMS", "Did not get WKID");
     525               0 :         return NULL;
     526                 :     }
     527               1 :     if (!bHasMinX)
     528                 :     {
     529               0 :         CPLDebug("WMS", "Did not get min x");
     530               0 :         return NULL;
     531                 :     }
     532               1 :     if (!bHasMaxY)
     533                 :     {
     534               0 :         CPLDebug("WMS", "Did not get max y");
     535               0 :         return NULL;
     536                 :     }
     537                 :     
     538               1 :     if (nWKID == 102100)
     539               1 :         nWKID = 3857;
     540                 : 
     541               1 :     const char* pszEndURL = strstr(pszURL, "/MapServer?f=json");
     542               1 :     CPLAssert(pszEndURL);
     543               1 :     CPLString osURL(pszURL);
     544               1 :     osURL.resize(pszEndURL - pszURL);
     545                 : 
     546               1 :     double dfMaxX = dfMinX + dfBaseResolution * nTileWidth;
     547               1 :     double dfMinY = dfMaxY - dfBaseResolution * nTileHeight;
     548                 : 
     549               1 :     int nTileCountX = 1;
     550               1 :     if (fabs(dfMinX - -180) < 1e-4 && fabs(dfMaxY - 90) < 1e-4 &&
     551                 :         fabs(dfMinY - -90) < 1e-4)
     552                 :     {
     553               0 :         nTileCountX = 2;
     554               0 :         dfMaxX = 180;
     555                 :     }
     556                 : 
     557                 :     CPLString osXML = CPLSPrintf(
     558                 :             "<GDAL_WMS>\n"
     559                 :             "  <Service name=\"TMS\">\n"
     560                 :             "    <ServerUrl>%s/MapServer/tile/${z}/${y}/${x}</ServerUrl>\n"
     561                 :             "  </Service>\n"
     562                 :             "  <DataWindow>\n"
     563                 :             "    <UpperLeftX>%.8f</UpperLeftX>\n"
     564                 :             "    <UpperLeftY>%.8f</UpperLeftY>\n"
     565                 :             "    <LowerRightX>%.8f</LowerRightX>\n"
     566                 :             "    <LowerRightY>%.8f</LowerRightY>\n"
     567                 :             "    <TileLevel>%d</TileLevel>\n"
     568                 :             "    <TileCountX>%d</TileCountX>\n"
     569                 :             "    <YOrigin>top</YOrigin>\n"
     570                 :             "  </DataWindow>\n"
     571                 :             "  <Projection>EPSG:%d</Projection>\n"
     572                 :             "  <BlockSizeX>%d</BlockSizeX>\n"
     573                 :             "  <BlockSizeY>%d</BlockSizeY>\n"
     574                 :             "  <Cache/>\n"
     575                 :             "</GDAL_WMS>\n",
     576                 :             osURL.c_str(),
     577                 :             dfMinX, dfMaxY, dfMaxX, dfMinY,
     578                 :             nLevelCount,
     579                 :             nTileCountX,
     580                 :             nWKID,
     581               1 :             nTileWidth, nTileHeight);
     582               1 :     CPLDebug("WMS", "Opening TMS :\n%s", osXML.c_str());
     583                 : 
     584               1 :     return CPLParseXMLString(osXML);
     585                 : }
     586                 : 
     587                 : /************************************************************************/
     588                 : /*                             Identify()                               */
     589                 : /************************************************************************/
     590                 : 
     591            9245 : int GDALWMSDataset::Identify(GDALOpenInfo *poOpenInfo)
     592                 : {
     593            9245 :     const char* pszFilename = poOpenInfo->pszFilename;
     594            9245 :     const char* pabyHeader = (const char *) poOpenInfo->pabyHeader;
     595            9245 :     if (poOpenInfo->nHeaderBytes == 0 &&
     596                 :          EQUALN(pszFilename, "<GDAL_WMS>", 10))
     597                 :     {
     598               0 :         return TRUE;
     599                 :     }
     600            9245 :     else if (poOpenInfo->nHeaderBytes >= 10 &&
     601                 :              EQUALN(pabyHeader, "<GDAL_WMS>", 10))
     602                 :     {
     603               0 :         return TRUE;
     604                 :     }
     605            9245 :     else if (poOpenInfo->nHeaderBytes == 0 &&
     606                 :              (EQUALN(pszFilename, "WMS:", 4) ||
     607                 :              CPLString(pszFilename).ifind("SERVICE=WMS") != std::string::npos) )
     608                 :     {
     609               0 :         return TRUE;
     610                 :     }
     611            9245 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     612                 :              (strstr(pabyHeader, "<WMT_MS_Capabilities") != NULL ||
     613                 :               strstr(pabyHeader, "<WMS_Capabilities") != NULL ||
     614                 :               strstr(pabyHeader, "<!DOCTYPE WMT_MS_Capabilities") != NULL))
     615                 :     {
     616               0 :         return TRUE;
     617                 :     }
     618            9245 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     619                 :              strstr(pabyHeader, "<WMS_Tile_Service") != NULL)
     620                 :     {
     621               0 :         return TRUE;
     622                 :     }
     623            9245 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     624                 :              strstr(pabyHeader, "<TileMap version=\"1.0.0\"") != NULL)
     625                 :     {
     626               0 :         return TRUE;
     627                 :     }
     628            9245 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     629                 :              strstr(pabyHeader, "<Services") != NULL &&
     630                 :              strstr(pabyHeader, "<TileMapService version=\"1.0") != NULL)
     631                 :     {
     632               0 :         return TRUE;
     633                 :     }
     634            9245 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     635                 :              strstr(pabyHeader, "<TileMapService version=\"1.0.0\"") != NULL)
     636                 :     {
     637               0 :         return TRUE;
     638                 :     }
     639            9245 :     else if (poOpenInfo->nHeaderBytes == 0 &&
     640                 :              EQUALN(pszFilename, "http", 4) &&
     641                 :              strstr(pszFilename, "/MapServer?f=json") != NULL)
     642                 :     {
     643               0 :         return TRUE;
     644                 :     }
     645                 :     else
     646            9245 :         return FALSE;
     647                 : }
     648                 : 
     649                 : /************************************************************************/
     650                 : /*                                 Open()                               */
     651                 : /************************************************************************/
     652                 : 
     653            2130 : GDALDataset *GDALWMSDataset::Open(GDALOpenInfo *poOpenInfo)
     654                 : {
     655            2130 :     CPLXMLNode *config = NULL;
     656            2130 :     CPLErr ret = CE_None;
     657                 : 
     658            2130 :     const char* pszFilename = poOpenInfo->pszFilename;
     659            2130 :     const char* pabyHeader = (const char *) poOpenInfo->pabyHeader;
     660                 : 
     661            2135 :     if (poOpenInfo->nHeaderBytes == 0 &&
     662                 :         EQUALN(pszFilename, "<GDAL_WMS>", 10))
     663                 :     {
     664               5 :         config = CPLParseXMLString(pszFilename);
     665                 :     }
     666            2126 :     else if (poOpenInfo->nHeaderBytes >= 10 &&
     667                 :              EQUALN(pabyHeader, "<GDAL_WMS>", 10))
     668                 :     {
     669               1 :         config = CPLParseXMLFile(pszFilename);
     670                 :     }
     671            2125 :     else if (poOpenInfo->nHeaderBytes == 0 &&
     672                 :              (EQUALN(pszFilename, "WMS:http", 8) ||
     673                 :               EQUALN(pszFilename, "http", 4)) &&
     674                 :              strstr(pszFilename, "/MapServer?f=json") != NULL)
     675                 :     {
     676               1 :         if (EQUALN(pszFilename, "WMS:http", 8))
     677               0 :             pszFilename += 4;
     678               1 :         CPLString osURL(pszFilename);
     679               1 :         if (strstr(pszFilename, "&pretty=true") == NULL)
     680               0 :             osURL += "&pretty=true";
     681               1 :         CPLHTTPResult *psResult = CPLHTTPFetch(osURL.c_str(), NULL);
     682               1 :         if (psResult == NULL)
     683               0 :             return NULL;
     684               1 :         if (psResult->pabyData == NULL)
     685                 :         {
     686               0 :             CPLHTTPDestroyResult(psResult);
     687               0 :             return NULL;
     688                 :         }
     689                 :         config = GDALWMSDatasetGetConfigFromArcGISJSON(osURL,
     690               1 :                                                        (const char*)psResult->pabyData);
     691               1 :         CPLHTTPDestroyResult(psResult);
     692                 :     }
     693                 : 
     694            2123 :     else if (poOpenInfo->nHeaderBytes == 0 &&
     695                 :              (EQUALN(pszFilename, "WMS:", 4) ||
     696                 :               CPLString(pszFilename).ifind("SERVICE=WMS") != std::string::npos))
     697                 :     {
     698               4 :         CPLString osLayers = CPLURLGetValue(pszFilename, "LAYERS");
     699               4 :         CPLString osRequest = CPLURLGetValue(pszFilename, "REQUEST");
     700               4 :         if (osLayers.size() != 0)
     701               2 :             config = GDALWMSDatasetGetConfigFromURL(poOpenInfo);
     702               2 :         else if (EQUAL(osRequest, "GetTileService"))
     703               1 :             return GDALWMSMetaDataset::DownloadGetTileService(poOpenInfo);
     704                 :         else
     705               1 :             return GDALWMSMetaDataset::DownloadGetCapabilities(poOpenInfo);
     706                 :     }
     707            2119 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     708                 :              (strstr(pabyHeader, "<WMT_MS_Capabilities") != NULL ||
     709                 :               strstr(pabyHeader, "<WMS_Capabilities") != NULL ||
     710                 :               strstr(pabyHeader, "<!DOCTYPE WMT_MS_Capabilities") != NULL))
     711                 :     {
     712               0 :         CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
     713               0 :         if (psXML == NULL)
     714               0 :             return NULL;
     715               0 :         GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeGetCapabilities(psXML);
     716               0 :         CPLDestroyXMLNode( psXML );
     717               0 :         return poRet;
     718                 :     }
     719            2119 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     720                 :              strstr(pabyHeader, "<WMS_Tile_Service") != NULL)
     721                 :     {
     722               0 :         CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
     723               0 :         if (psXML == NULL)
     724               0 :             return NULL;
     725               0 :         GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeGetTileService(psXML);
     726               0 :         CPLDestroyXMLNode( psXML );
     727               0 :         return poRet;
     728                 :     }
     729            2119 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     730                 :              strstr(pabyHeader, "<TileMap version=\"1.0.0\"") != NULL)
     731                 :     {
     732               0 :         CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
     733               0 :         if (psXML == NULL)
     734               0 :             return NULL;
     735               0 :         config = GDALWMSDatasetGetConfigFromTileMap(psXML);
     736               0 :         CPLDestroyXMLNode( psXML );
     737                 :     }
     738            2119 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     739                 :              strstr(pabyHeader, "<Services") != NULL &&
     740                 :              strstr(pabyHeader, "<TileMapService version=\"1.0") != NULL)
     741                 :     {
     742               0 :         CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
     743               0 :         if (psXML == NULL)
     744               0 :             return NULL;
     745               0 :         CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=Services" );
     746               0 :         GDALDataset* poRet = NULL;
     747               0 :         if (psRoot)
     748                 :         {
     749               0 :             CPLXMLNode* psTileMapService = CPLGetXMLNode(psRoot, "TileMapService");
     750               0 :             if (psTileMapService)
     751                 :             {
     752               0 :                 const char* pszHref = CPLGetXMLValue(psTileMapService, "href", NULL);
     753               0 :                 if (pszHref)
     754                 :                 {
     755               0 :                     poRet = (GDALDataset*) GDALOpen(pszHref, GA_ReadOnly);
     756                 :                 }
     757                 :             }
     758                 :         }
     759               0 :         CPLDestroyXMLNode( psXML );
     760               0 :         return poRet;
     761                 :     }
     762            2119 :     else if (poOpenInfo->nHeaderBytes != 0 &&
     763                 :              strstr(pabyHeader, "<TileMapService version=\"1.0.0\"") != NULL)
     764                 :     {
     765               0 :         CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
     766               0 :         if (psXML == NULL)
     767               0 :             return NULL;
     768               0 :         GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeTileMapService(psXML);
     769               0 :         CPLDestroyXMLNode( psXML );
     770               0 :         return poRet;
     771                 :     }
     772                 :     else
     773            2119 :         return NULL;
     774               9 :     if (config == NULL) return NULL;
     775                 : 
     776                 : /* -------------------------------------------------------------------- */
     777                 : /*      Confirm the requested access is supported.                      */
     778                 : /* -------------------------------------------------------------------- */
     779               9 :     if( poOpenInfo->eAccess == GA_Update )
     780                 :     {
     781               0 :         CPLDestroyXMLNode(config);
     782                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     783                 :                   "The WMS driver does not support update access to existing"
     784               0 :                   " datasets.\n" );
     785               0 :         return NULL;
     786                 :     }
     787                 : 
     788               9 :     GDALWMSDataset *ds = new GDALWMSDataset();
     789               9 :     ret = ds->Initialize(config);
     790               9 :     if (ret != CE_None) {
     791               0 :         delete ds;
     792               0 :         ds = NULL;
     793                 :     }
     794               9 :     CPLDestroyXMLNode(config);
     795                 : 
     796                 : /* -------------------------------------------------------------------- */
     797                 : /*      Initialize any PAM information.                                 */
     798                 : /* -------------------------------------------------------------------- */
     799               9 :     if (ds != NULL)
     800                 :     {
     801               9 :         ds->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
     802               9 :         ds->SetDescription( poOpenInfo->pszFilename );
     803               9 :         ds->TryLoadXML();
     804                 :     }
     805                 : 
     806               9 :     return ds;
     807                 : }
     808                 : /************************************************************************/
     809                 : /*                             CreateCopy()                             */
     810                 : /************************************************************************/
     811                 : 
     812              19 : GDALDataset *GDALWMSDataset::CreateCopy( const char * pszFilename,
     813                 :                                          GDALDataset *poSrcDS,
     814                 :                                          int bStrict, char ** papszOptions,
     815                 :                                          GDALProgressFunc pfnProgress,
     816                 :                                          void * pProgressData )
     817                 : {
     818              57 :     if (poSrcDS->GetDriver() == NULL ||
     819              38 :         !EQUAL(poSrcDS->GetDriver()->GetDescription(), "WMS"))
     820                 :     {
     821                 :         CPLError(CE_Failure, CPLE_NotSupported,
     822              18 :                  "Source dataset must be a WMS dataset");
     823              18 :         return NULL;
     824                 :     }
     825                 : 
     826               1 :     const char* pszXML = poSrcDS->GetMetadataItem("XML", "WMS");
     827               1 :     if (pszXML == NULL)
     828                 :     {
     829                 :         CPLError(CE_Failure, CPLE_AppDefined,
     830               0 :                  "Cannot get XML definition of source WMS dataset");
     831               0 :         return NULL;
     832                 :     }
     833                 : 
     834               1 :     VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
     835               1 :     if (fp == NULL)
     836               0 :         return NULL;
     837                 : 
     838               1 :     VSIFWriteL(pszXML, 1, strlen(pszXML), fp);
     839               1 :     VSIFCloseL(fp);
     840                 : 
     841               1 :     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     842               1 :     return Open(&oOpenInfo);
     843                 : }
     844                 : 
     845                 : /************************************************************************/
     846                 : /*                         GDALDeregister_WMS()                         */
     847                 : /************************************************************************/
     848                 : 
     849             522 : static void GDALDeregister_WMS( GDALDriver * )
     850                 : 
     851                 : {
     852             522 :     DestroyWMSMiniDriverManager();
     853             522 : }
     854                 : 
     855                 : /************************************************************************/
     856                 : /*                          GDALRegister_WMS()                          */
     857                 : /************************************************************************/
     858                 : 
     859             558 : void GDALRegister_WMS() {
     860                 :     GDALDriver *driver;
     861             558 :     if (GDALGetDriverByName("WMS") == NULL) {
     862             537 :         driver = new GDALDriver();
     863             537 :         driver->SetDescription("WMS");
     864             537 :         driver->SetMetadataItem(GDAL_DMD_LONGNAME, "OGC Web Map Service");
     865             537 :         driver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "frmt_wms.html");
     866             537 :         driver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     867             537 :         driver->pfnOpen = GDALWMSDataset::Open;
     868             537 :         driver->pfnIdentify = GDALWMSDataset::Identify;
     869             537 :         driver->pfnUnloadDriver = GDALDeregister_WMS;
     870             537 :         driver->pfnCreateCopy = GDALWMSDataset::CreateCopy;
     871             537 :         GetGDALDriverManager()->RegisterDriver(driver);
     872                 : 
     873             537 :         GDALWMSMiniDriverManager *const mdm = GetGDALWMSMiniDriverManager();
     874            1074 :         mdm->Register(new GDALWMSMiniDriverFactory_WMS());
     875            1074 :         mdm->Register(new GDALWMSMiniDriverFactory_TileService());
     876            1074 :         mdm->Register(new GDALWMSMiniDriverFactory_WorldWind());
     877            1074 :         mdm->Register(new GDALWMSMiniDriverFactory_TMS());
     878            1074 :         mdm->Register(new GDALWMSMiniDriverFactory_TiledWMS());
     879            1074 :         mdm->Register(new GDALWMSMiniDriverFactory_VirtualEarth());
     880                 :     }
     881             558 : }

Generated by: LCOV version 1.7