LCOV - code coverage report
Current view: directory - frmts/wms - minidriver_tiled_wms.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 234 185 79.1 %
Date: 2011-12-18 Functions: 24 16 66.7 %

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Project:  WMS Client Driver
       4                 :  * Purpose:  Implementation of the OnEarth Tiled WMS minidriver.
       5                 :  *           http://onearth.jpl.nasa.gov/tiled.html
       6                 :  * Author:   Lucian Plesea (Lucian dot Pleasea at jpl.nasa.gov)
       7                 :  *           Adam Nowacki
       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                 : 
      33            1061 : CPP_GDALWMSMiniDriverFactory(TiledWMS)
      34                 : 
      35                 : /************************************************************************/
      36                 : /*                           SearchXMLSiblings()                        */
      37                 : /************************************************************************/
      38                 : 
      39                 : /*
      40                 :  * \brief Search for a sibling of the root node with a given name.
      41                 :  *
      42                 :  * Searches only the next siblings of the node passed in for the named element or attribute.
      43                 :  * If the first character of the pszElement is '=', the search includes the psRoot node
      44                 :  * 
      45                 :  * @param psRoot the root node to search.  This should be a node of type
      46                 :  * CXT_Element.  NULL is safe.
      47                 :  *
      48                 :  * @param pszElement the name of the element or attribute to search for.
      49                 :  *
      50                 :  *
      51                 :  * @return The first matching node or NULL on failure. 
      52                 :  */
      53                 : 
      54              26 : static CPLXMLNode *SearchXMLSiblings( CPLXMLNode *psRoot, const char *pszElement )
      55                 : 
      56                 : {
      57              26 :     if( psRoot == NULL || pszElement == NULL )
      58               0 :         return NULL;
      59                 : 
      60                 :     // If the strings starts with '=', include the current node
      61              26 :     if (pszElement[0]=='=') {
      62              24 :   if (EQUAL(psRoot->pszValue,pszElement+1))
      63              22 :       return psRoot;
      64               2 :   else return SearchXMLSiblings(psRoot,pszElement+1);
      65                 :     }
      66                 : 
      67                 :     // Only search the siblings, starting with psRoot->psNext
      68              13 :     for (psRoot=psRoot->psNext;psRoot!=NULL;psRoot=psRoot->psNext) {
      69              13 :   if ( (psRoot->eType == CXT_Element ||
      70                 :               psRoot->eType == CXT_Attribute)
      71                 :        && EQUAL(pszElement,psRoot->pszValue) )
      72               2 :             return psRoot;
      73                 :     }
      74                 : 
      75               0 :     return NULL;
      76                 : }
      77                 : 
      78                 : /************************************************************************/
      79                 : /*                        SearchLeafGroupName()                         */
      80                 : /************************************************************************/
      81                 : 
      82                 : /*
      83                 :  * \brief Search for a leaf TileGroup node by name.
      84                 :  *
      85                 :  * @param psRoot the root node to search.  This should be a node of type
      86                 :  * CXT_Element.  NULL is safe.
      87                 :  *
      88                 :  * @param pszElement the name of the TileGroup to search for.
      89                 :  *
      90                 :  * @return The XML node of the matching TileGroup or NULL on failure.
      91                 :  */
      92                 : 
      93              75 : static CPLXMLNode *SearchLeafGroupName( CPLXMLNode *psRoot, const char *name )
      94                 : 
      95                 : {
      96              75 :     CPLXMLNode *ret=NULL;
      97                 : 
      98              75 :     if( psRoot == NULL || name == NULL ) return NULL;
      99                 : 
     100                 :     // Has to be a leaf TileGroup with the right name
     101              71 :     if (NULL==CPLSearchXMLNode(psRoot->psChild,"=TiledGroup"))
     102                 :     {
     103              67 :         if (EQUAL(name,CPLGetXMLValue(psRoot,"Name","")))
     104                 :         {
     105               2 :             return psRoot;
     106                 :         }
     107                 :         else
     108                 :         { // Try a sibling
     109              65 :             return SearchLeafGroupName(psRoot->psNext,name);
     110                 :         }
     111                 :     }
     112                 :     else
     113                 :     { // Is metagroup, try children then siblings
     114               4 :         ret=SearchLeafGroupName(psRoot->psChild,name);
     115               4 :         if (NULL!=ret) return ret;
     116               4 :         return SearchLeafGroupName(psRoot->psNext,name);
     117                 :     }
     118                 : }
     119                 : 
     120                 : /************************************************************************/
     121                 : /*                             BandInterp()                             */
     122                 : /************************************************************************/
     123                 : 
     124                 : /*
     125                 :  * \brief Utility function to calculate color band interpretation.
     126                 :  * Only handles Gray, GrayAlpha, RGB and RGBA, based on total band count
     127                 :  *
     128                 :  * @param nbands is the total number of bands in the image
     129                 :  *
     130                 :  * @param band is the band number, starting with 1
     131                 :  *
     132                 :  * @return GDALColorInterp of the band
     133                 :  */
     134                 : 
     135               4 : static GDALColorInterp BandInterp(int nbands, int band) {
     136               4 :     switch (nbands) {
     137               1 :       case 1: return GCI_GrayIndex;
     138               0 :       case 2: return ((band==1)?GCI_GrayIndex:GCI_AlphaBand);
     139                 :       case 3: // RGB
     140                 :       case 4: // RBGA
     141               3 :         if (band<3)
     142               2 :             return ((band==1)?GCI_RedBand:GCI_GreenBand);
     143               1 :         return ((band==3)?GCI_BlueBand:GCI_AlphaBand);
     144                 :       default:
     145               0 :         return GCI_Undefined;
     146                 :     }
     147                 : }
     148                 : 
     149                 : /************************************************************************/
     150                 : /*                              FindBbox()                              */
     151                 : /************************************************************************/
     152                 : 
     153                 : /*
     154                 :  * \brief Utility function to find the position of the bbox parameter value 
     155                 :  * within a request string.  The search for the bbox is case insensitive
     156                 :  *
     157                 :  * @param in, the string to search into
     158                 :  *
     159                 :  * @return The position from the begining of the string or -1 if not found
     160                 :  */
     161                 : 
     162             205 : static int FindBbox(CPLString in) {
     163                 : 
     164             205 :     size_t pos = in.ifind("&bbox=");
     165             205 :     if (pos == std::string::npos)
     166               0 :         return -1;
     167                 :     else
     168             205 :         return (int)pos + 6;
     169                 : }
     170                 : 
     171                 : /************************************************************************/
     172                 : /*                         FindChangePattern()                          */
     173                 : /************************************************************************/
     174                 : 
     175                 : /*
     176                 :  * \brief Utility function to pick the right request pattern based on
     177                 :  * the change request list
     178                 :  *
     179                 :  * @param cdata, the list of possible requests, white space separated
     180                 :  * @param substs, the list of substitutions
     181                 :  * @param ret The best match request
     182                 :  */
     183                 : 
     184              24 : void FindChangePattern( char *cdata,char **substs, CPLString &ret) {
     185                 :     char **papszTokens=CSLTokenizeString2(cdata," \t\n\r",
     186              24 :                                           CSLT_STRIPLEADSPACES|CSLT_STRIPENDSPACES);
     187                 : 
     188              24 :     int matchcount=CSLCount(substs);
     189              24 :     for (int j=0;j<CSLCount(papszTokens);j++)
     190                 :     {
     191              24 :         int thiscount=0;
     192              24 :         CPLString this_string=papszTokens[j];
     193              24 :         for (int i=0;i<matchcount;i++) {
     194               0 :             char *key = NULL;
     195               0 :             CPLParseNameValue(substs[i],&key);
     196               0 :             if (key)
     197                 :             {
     198               0 :                 if (std::string::npos!=this_string.find(key,0))
     199               0 :                     thiscount++;
     200               0 :                 CPLFree(key);
     201                 :             }
     202                 :         }
     203              24 :         if (thiscount==matchcount) {
     204              24 :             ret=papszTokens[j];
     205                 :             break;
     206                 :         }
     207                 :     }
     208                 : 
     209                 :     // if no match is found, return first string
     210              24 :     if (ret.empty()) ret=papszTokens[0];
     211              24 :     CSLDestroy(papszTokens);
     212              24 : }
     213                 : 
     214               2 : GDALWMSMiniDriver_TiledWMS::GDALWMSMiniDriver_TiledWMS() {
     215               2 :     m_requests = NULL;
     216               2 :     m_substs = NULL;
     217               2 : }
     218                 : 
     219               2 : GDALWMSMiniDriver_TiledWMS::~GDALWMSMiniDriver_TiledWMS() {
     220               2 :     CSLDestroy(m_requests);
     221               2 :     CSLDestroy(m_substs);
     222               2 : }
     223                 : 
     224                 : 
     225                 : // Returns the scale of a WMS request as compared to the base resolution
     226             181 : double GDALWMSMiniDriver_TiledWMS::Scale(const char *request) {
     227             181 :     int bbox=FindBbox(request);
     228             181 :     if (bbox<0) return 0;
     229                 :     double x,y,X,Y;
     230             181 :     sscanf(request+bbox,"%lf,%lf,%lf,%lf",&x,&y,&X,&Y);
     231             181 :     return (m_data_window.m_x1-m_data_window.m_x0)/(X-x)*m_bsx/m_data_window.m_sx;
     232                 : }
     233                 : 
     234                 : 
     235                 : // Finds, extracts, and returns the highest resolution request string from a list, starting at item i
     236              24 : void GDALWMSMiniDriver_TiledWMS::GetLowestScale(char **& list,int i, CPLString &req) {
     237              24 :     req="";
     238              24 :     double scale=-1;
     239              24 :     int position=-1;
     240             205 :     while (NULL!=list[i]) {
     241             157 :   double tscale=Scale(list[i]);
     242             157 :   if (tscale>=scale) {
     243             102 :       scale=tscale;
     244             102 :       position=i;
     245                 :   }
     246             157 :   i++;
     247                 :     }
     248              24 :     if (position>-1) {
     249              24 :         req=list[position];
     250              24 :         list = CSLRemoveStrings(list,position,1,NULL);
     251                 :     }
     252              24 : }
     253                 : 
     254                 : 
     255               2 : CPLErr GDALWMSMiniDriver_TiledWMS::Initialize(CPLXMLNode *config) {
     256               2 :     CPLErr ret = CE_None;
     257               2 :     CPLXMLNode *tileServiceConfig=NULL;
     258               2 :     CPLHTTPResult *psResult=NULL;
     259               2 :     CPLXMLNode *TG=NULL;
     260                 : 
     261               2 :     char **requests=NULL;
     262               2 :     char **substs=NULL;
     263                 : 
     264               2 :     for (int once=1;once;once--) { // Something to break out of
     265                 :         // Parse info from the service
     266                 : 
     267               2 :         m_end_url = CPLGetXMLValue(config,"AdditionalArgs","");
     268               4 :         m_base_url = CPLGetXMLValue(config, "ServerURL", "");
     269               2 :         if (m_base_url.empty()) {
     270               0 :             CPLError(ret=CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: ServerURL missing.");
     271               0 :             break;
     272                 :         }
     273                 : 
     274               2 :         m_tiledGroupName = CPLGetXMLValue(config, "TiledGroupName", "");
     275               2 :         if (m_tiledGroupName.empty()) {
     276               0 :             CPLError(ret=CE_Failure, CPLE_AppDefined, "GDALWMS, Tiled WMS: TiledGroupName missing.");
     277               0 :             break;
     278                 :         }
     279                 : 
     280                 :         // Change strings, key is an attribute, value is the value of the Change node
     281                 :         // Multiple substitutions are possible
     282               2 :         TG=CPLSearchXMLNode(config, "Change");
     283               2 :         while(TG!=NULL) {
     284               0 :             CPLString name=CPLGetXMLValue(TG,"key","");
     285               0 :             if (!name.empty()) {
     286               0 :                 CPLString value=CPLGetXMLValue(TG,"","");
     287               0 :                 substs=CSLSetNameValue(substs,name,value);
     288                 :             } else {
     289                 :                 CPLError(ret=CE_Failure, CPLE_AppDefined, "GDALWMS, Tiled WMS: Syntax error in configuration file.\n"
     290               0 :                          "Change element needs a non-empty \"key\" attribute");
     291                 :                 break;
     292                 :             }
     293               0 :             TG=SearchXMLSiblings(TG,"Change");
     294                 :         }
     295               2 :         if (ret!=CE_None) break;
     296                 : 
     297               2 :         CPLString getTileServiceUrl = m_base_url + "request=GetTileService";
     298               2 :         psResult = CPLHTTPFetch(getTileServiceUrl, NULL);
     299                 : 
     300               2 :         if (NULL==psResult) {
     301                 :             CPLError(ret=CE_Failure, CPLE_AppDefined, 
     302               0 :                      "GDALWMS, Tiled WMS: Can't use GDAL HTTP, no curl support.");
     303                 :             break;
     304                 :         }
     305                 : 
     306               2 :         if ((psResult->nStatus!=0)||(NULL==psResult->pabyData)||('\0'==psResult->pabyData[0])) {
     307                 :             CPLError(ret=CE_Failure, CPLE_AppDefined,
     308               0 :                      "GDALWMS, Tiled WMS: Can't get server response to GetTileService.");
     309                 :             break;
     310                 :         }
     311                 : 
     312               2 :         if (NULL==(tileServiceConfig=CPLParseXMLString((const char*)psResult->pabyData))) {
     313               0 :             CPLError(ret=CE_Failure,CPLE_AppDefined, "GDALWMS, Tiled WMS: Error parsing the GetTileService response.");
     314                 :             break;
     315                 :         }
     316                 :     
     317               2 :         m_base_url=CPLGetXMLValue(tileServiceConfig,"TiledPatterns.OnlineResource.xlink:href","");
     318               2 :         if (m_base_url.empty()) {
     319               0 :             CPLError(ret=CE_Failure,CPLE_AppDefined, "GDALWMS, Tiled WMS: Can't locate OnlineResource in the server response.");
     320                 :             break;
     321                 :         }
     322                 :     
     323               2 :         if (NULL==(TG=CPLSearchXMLNode(tileServiceConfig, "TiledPatterns"))) {
     324                 :             CPLError(ret=CE_Failure,CPLE_AppDefined, 
     325               0 :                      "GDALWMS, Tiled WMS: Can't locate TiledPatterns in server response.");
     326                 :             break;
     327                 :         }
     328                 :     
     329               2 :         if (NULL==(TG=SearchLeafGroupName(TG->psChild,m_tiledGroupName))) {
     330                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,
     331               0 :                      "GDALWMS, Tiled WMS: Can't locate TiledGroup in server response.");
     332                 :             break;
     333                 :         }
     334                 : 
     335               2 :         if (0>(m_bands_count=atoi(CPLGetXMLValue(TG, "Bands", "3")))) {
     336                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,
     337               0 :                      "GDALWMS, Tiled WMS: Invalid number of bands in server response");
     338                 :             break;
     339                 :         }
     340               2 :         if (!GDALCheckBandCount(m_bands_count, FALSE))
     341                 :         {
     342               0 :             ret = CE_Failure;
     343                 :             break;
     344                 :         }
     345                 : 
     346               2 :         m_parent_dataset->WMSSetBandsCount(m_bands_count);
     347               2 :         m_parent_dataset->WMSSetDataType(GDALGetDataTypeByName(CPLGetXMLValue(TG, "DataType", "Byte")));
     348               2 :         m_projection_wkt=CPLGetXMLValue(TG, "Projection","");
     349                 : 
     350                 :         // Bounding box for the group itself
     351               2 :         CPLXMLNode *latlonbbox = CPLSearchXMLNode(TG, "LatLonBoundingBox");
     352               2 :         if (NULL==latlonbbox) {
     353                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,
     354               0 :                      "GDALWMS, Tiled WMS: Can't locate the LatLonBoundingBox in server response.");
     355                 :             break;
     356                 :         }
     357                 : 
     358               2 :         m_data_window.m_x0=atof(CPLGetXMLValue(latlonbbox,"minx","0"));
     359               2 :         m_data_window.m_x1=atof(CPLGetXMLValue(latlonbbox,"maxx","-1"));
     360               2 :         m_data_window.m_y0=atof(CPLGetXMLValue(latlonbbox,"maxy","0"));
     361               2 :         m_data_window.m_y1=atof(CPLGetXMLValue(latlonbbox,"miny","-1"));
     362                 : 
     363               2 :         if ((m_data_window.m_x1-m_data_window.m_x0)<0) {
     364                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,
     365               0 :                      "GDALWMS, Tiled WMS: Coordinate order in boundingbox problem in server response.");
     366                 :             break;
     367                 :         }
     368                 : 
     369               2 :         m_overview_count=0;
     370               2 :         CPLXMLNode *Pattern=TG->psChild;
     371                 : 
     372               2 :         m_bsx=m_bsy=-1;
     373               2 :         m_data_window.m_sx=m_data_window.m_sy=0;
     374                 : 
     375               4 :         for (int once=1;once;once--) { // Something to break out of
     376               2 :             while ((NULL!=Pattern)&&(NULL!=(Pattern=SearchXMLSiblings(Pattern,"=TilePattern")))) {
     377                 :                 int mbsx,mbsy;
     378                 : 
     379              24 :                 CPLString request;
     380              24 :                 FindChangePattern(Pattern->psChild->pszValue,substs,request);
     381                 : 
     382              24 :                 char **papszTokens=CSLTokenizeString2(request,"&",0);
     383                 : 
     384              24 :                 mbsx=atoi(CSLFetchNameValue(papszTokens,"WIDTH"));
     385              24 :                 mbsy=atoi(CSLFetchNameValue(papszTokens,"HEIGHT"));
     386              24 :                 if (m_projection_wkt.empty()) {
     387               2 :                     const char* pszSRS = CSLFetchNameValue(papszTokens,"SRS");
     388               2 :                     m_projection_wkt = (pszSRS) ? pszSRS : "";
     389               2 :                     if (!m_projection_wkt.empty())
     390               2 :                         m_projection_wkt=ProjToWKT(m_projection_wkt);
     391                 :                 }
     392                 : 
     393              24 :                 if (-1==m_bsx) m_bsx=mbsx;
     394              24 :                 if (-1==m_bsy) m_bsy=mbsy;
     395              24 :                 if ((m_bsy!=mbsy)||(m_bsy!=mbsy)) {
     396                 :                     CPLError(ret=CE_Failure,CPLE_AppDefined,
     397               0 :                              "GDALWMS, Tiled WMS: Tileset uses different block sizes.");
     398               0 :                     m_overview_count=0;
     399               0 :                     CSLDestroy(papszTokens);
     400                 :                     break;
     401                 :                 }
     402                 : 
     403              24 :                 const char* pszBBOX = CSLFetchNameValue(papszTokens,"BBOX");
     404              24 :                 if (pszBBOX == NULL)
     405                 :                 {
     406                 :                     CPLError(ret=CE_Failure,CPLE_AppDefined,
     407               0 :                         "GDALWMS, Tiled WMS: BBOX parameter not found in server response.");
     408               0 :                     CSLDestroy(papszTokens);
     409                 :                     break;
     410                 :                 }
     411                 : 
     412                 :                 double x,y,X,Y;
     413              24 :                 if (sscanf(pszBBOX,"%lf,%lf,%lf,%lf",&x,&y,&X,&Y) != 4)
     414                 :                 {
     415                 :                     CPLError(ret=CE_Failure,CPLE_AppDefined,
     416               0 :                         "GDALWMS, Tiled WMS: Invalid value for BBOX parameter in server response.");
     417               0 :                     CSLDestroy(papszTokens);
     418                 :                     break;
     419                 :                 }
     420              24 :                 int sx=static_cast<int>((m_data_window.m_x1-m_data_window.m_x0)/(X-x)*m_bsx);
     421              24 :                 int sy=static_cast<int>(fabs((m_data_window.m_y1-m_data_window.m_y0)/(Y-y)*m_bsy));
     422              24 :                 if (sx>m_data_window.m_sx) m_data_window.m_sx=sx;
     423              24 :                 if (sy>m_data_window.m_sy) m_data_window.m_sy=sy;
     424              24 :                 CSLDestroy(papszTokens);
     425                 : 
     426                 :                 // Only use overlays where the top coordinate is within a pixel from the top of coverage
     427                 :                 double pix_off,temp;
     428              24 :                 pix_off=m_bsy*modf(fabs((Y-m_data_window.m_y0)/(Y-y)),&temp);
     429              48 :                 if ((pix_off<1)||((m_bsy-pix_off)<1)) {
     430              24 :                     requests=CSLAddString(requests,request);
     431              24 :                     m_overview_count++;
     432                 :                 } else
     433                 :                     CPLError(CE_Warning,CPLE_AppDefined,
     434               0 :                              "GDALWMS, Tiled WMS: Overlay size %dX%d can't be used due to alignment",sx,sy);
     435                 : 
     436              24 :                 Pattern=Pattern->psNext;
     437                 : 
     438                 :             }
     439                 : 
     440                 :             // The tlevel is needed, the tx and ty are not used by this minidriver
     441               2 :             m_data_window.m_tlevel = 0;
     442               2 :             m_data_window.m_tx = 0;
     443               2 :             m_data_window.m_ty = 0;
     444                 : 
     445                 :             // Make sure the parent_dataset values are set before creating the bands
     446               2 :             m_parent_dataset->WMSSetBlockSize(m_bsx,m_bsy);
     447               2 :             m_parent_dataset->WMSSetRasterSize(m_data_window.m_sx,m_data_window.m_sy);
     448                 : 
     449               2 :             m_parent_dataset->WMSSetDataWindow(m_data_window);
     450               2 :             m_parent_dataset->WMSSetOverviewCount(m_overview_count);
     451               2 :             m_parent_dataset->WMSSetClamp(false);
     452                 : 
     453                 :             // Ready for the Rasterband creation
     454                 :             int i;
     455               2 :             for (i=0;i<m_overview_count;i++) {
     456              24 :                 CPLString request="";
     457              24 :                 GetLowestScale(requests,i,request);
     458              24 :                 double scale=Scale(request);
     459                 : 
     460              24 :                 if (i == 0)
     461                 :                 {
     462               2 :                     if (fabs(scale-1.0) >1e-6)
     463                 :                     {
     464                 :                         CPLError(ret=CE_Failure,CPLE_AppDefined,
     465               0 :                          "GDALWMS, Tiled WMS: Did not get expected scale : %.15f", scale);
     466                 :                         break;
     467                 :                     }
     468                 :                 }
     469                 : 
     470                 :                 // Prepare the request and insert it back into the list
     471              24 :                 int startBbox=FindBbox(request);
     472              24 :                 int BboxSize=request.find_first_of("&",startBbox);
     473              24 :                 request.replace(startBbox,BboxSize,"${GDAL_BBOX}");
     474              24 :                 requests = CSLInsertString(requests,i,request);
     475                 : 
     476                 :                 // Create the Rasterband or overview
     477              74 :                 for (int j = 1; j <= m_bands_count; j++) {
     478              50 :                     if (i == 0) {
     479               4 :                         GDALWMSRasterBand *band=new GDALWMSRasterBand(m_parent_dataset, j, scale);
     480               4 :                         band->SetColorInterpretation(BandInterp(m_bands_count,j));
     481               4 :                         m_parent_dataset->mSetBand(j, band);
     482                 :                     } else
     483              46 :                         m_parent_dataset->mGetBand(j)->AddOverview(scale);
     484                 :                 }
     485                 :             }
     486                 : 
     487               2 :             if (i != m_overview_count)
     488               0 :                 break;
     489                 : 
     490               2 :             if ((m_overview_count==0)||(m_bsx<1)||(m_bsy<1)) {
     491                 :                 CPLError(ret=CE_Failure,CPLE_AppDefined,
     492               0 :                          "GDALWMS, Tiled WMS: No usable TilePattern elements found");
     493               0 :                 break;
     494                 :             }
     495                 :         }
     496                 :     }
     497                 : 
     498               2 :     m_requests=requests;
     499               2 :     m_substs=substs;
     500                 : 
     501               2 :     if (tileServiceConfig) CPLDestroyXMLNode(tileServiceConfig);
     502               2 :     if (psResult) CPLHTTPDestroyResult(psResult);
     503                 : 
     504               2 :     return ret;
     505                 : }
     506                 : 
     507               2 : void GDALWMSMiniDriver_TiledWMS::GetCapabilities(GDALWMSMiniDriverCapabilities *caps) {
     508               2 :     caps->m_capabilities_version = 1;
     509               2 :     caps->m_has_arb_overviews = 0;
     510               2 :     caps->m_has_image_request = 1;
     511               2 :     caps->m_has_tiled_image_requeset = 1;
     512               2 :     caps->m_max_overview_count = 32;
     513               2 : }
     514                 : 
     515                 : 
     516                 : // not called
     517               0 : void GDALWMSMiniDriver_TiledWMS::ImageRequest(CPLString *url, const GDALWMSImageRequestInfo &iri) {
     518               0 : }
     519                 : 
     520               2 : void GDALWMSMiniDriver_TiledWMS::TiledImageRequest(CPLString *url, const GDALWMSImageRequestInfo &iri, const GDALWMSTiledImageRequestInfo &tiri) {
     521               2 :     *url = m_base_url;
     522               2 :     URLAppend(url,CSLGetField(m_requests,-tiri.m_level));
     523                 :     URLSearchAndReplace(url,"${GDAL_BBOX}","%013.8f,%013.8f,%013.8f,%013.8f",
     524               2 :                         iri.m_x0,iri.m_y1,iri.m_x1,iri.m_y0);
     525               2 :     if (m_substs!=NULL) {
     526               0 :   for (int i=0;i<CSLCount(m_substs);i++) {
     527                 :       char *k;
     528               0 :       const char *v=CPLParseNameValue(m_substs[i],&k);
     529               0 :       URLSearchAndReplace(url,k,"%s",v);
     530               0 :       VSIFree(k);
     531                 :   }
     532                 :     }
     533               2 :     URLAppend(url,m_end_url);
     534               2 : }
     535                 : 
     536               2 : const char *GDALWMSMiniDriver_TiledWMS::GetProjectionInWKT() {
     537               2 :     return m_projection_wkt.c_str();
     538                 : }
     539                 : 

Generated by: LCOV version 1.7