LCOV - code coverage report
Current view: directory - frmts/wms - minidriver_tiled_wms.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 300 230 76.7 %
Date: 2012-12-26 Functions: 26 18 69.2 %

       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 Plesea 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            1106 : CPP_GDALWMSMiniDriverFactory(TiledWMS)
      34                 : 
      35                 : static char SIG[]="GDAL_WMS TiledWMS: ";
      36                 : 
      37                 : /*
      38                 :  *\brief Read a number from an xml element
      39                 :  */
      40                 : 
      41              36 : static double getXMLNum(CPLXMLNode *poRoot, const char *pszPath, const char *pszDefault)
      42                 : {
      43              36 :     return CPLAtof(CPLGetXMLValue(poRoot,pszPath,pszDefault));
      44                 : }
      45                 : 
      46                 : /*
      47                 :  *\brief Read a ColorEntry XML node, return a GDALColorEntry structure
      48                 :  *
      49                 :  */
      50                 : 
      51               7 : static GDALColorEntry GetXMLColorEntry(CPLXMLNode *p)
      52                 : {
      53                 :     GDALColorEntry ce;
      54               7 :     ce.c1= static_cast<short>(getXMLNum(p,"c1","0"));
      55               7 :     ce.c2= static_cast<short>(getXMLNum(p,"c2","0"));
      56               7 :     ce.c3= static_cast<short>(getXMLNum(p,"c3","0"));
      57               7 :     ce.c4= static_cast<short>(getXMLNum(p,"c4","255"));
      58               7 :     return ce;
      59                 : }
      60                 : 
      61                 : 
      62                 : /************************************************************************/
      63                 : /*                           SearchXMLSiblings()                        */
      64                 : /************************************************************************/
      65                 : 
      66                 : /*
      67                 :  * \brief Search for a sibling of the root node with a given name.
      68                 :  *
      69                 :  * Searches only the next siblings of the node passed in for the named element or attribute.
      70                 :  * If the first character of the pszElement is '=', the search includes the psRoot node
      71                 :  * 
      72                 :  * @param psRoot the root node to search.  This should be a node of type
      73                 :  * CXT_Element.  NULL is safe.
      74                 :  *
      75                 :  * @param pszElement the name of the element or attribute to search for.
      76                 :  *
      77                 :  *
      78                 :  * @return The first matching node or NULL on failure. 
      79                 :  */
      80                 : 
      81             228 : static CPLXMLNode *SearchXMLSiblings( CPLXMLNode *psRoot, const char *pszElement )
      82                 : 
      83                 : {
      84             228 :     if( psRoot == NULL || pszElement == NULL )
      85               0 :         return NULL;
      86                 : 
      87                 :     // If the strings starts with '=', skip it and test the root
      88                 :     // If not, start testing with the next sibling
      89             228 :     if (pszElement[0]=='=')
      90              39 :         pszElement++;
      91                 :     else
      92             189 :         psRoot=psRoot->psNext;
      93                 : 
      94            3460 :     for (;psRoot!=NULL;psRoot=psRoot->psNext)
      95                 :     {
      96            3281 :         if ((psRoot->eType == CXT_Element ||
      97                 :              psRoot->eType == CXT_Attribute)
      98                 :              && EQUAL(pszElement,psRoot->pszValue))
      99              49 :             return psRoot;
     100                 :     }
     101             179 :     return NULL;
     102                 : }
     103                 : 
     104                 : /************************************************************************/
     105                 : /*                        SearchLeafGroupName()                         */
     106                 : /************************************************************************/
     107                 : 
     108                 : /*
     109                 :  * \brief Search for a leaf TileGroup node by name.
     110                 :  *
     111                 :  * @param psRoot the root node to search.  This should be a node of type
     112                 :  * CXT_Element.  NULL is safe.
     113                 :  *
     114                 :  * @param pszElement the name of the TileGroup to search for.
     115                 :  *
     116                 :  * @return The XML node of the matching TileGroup or NULL on failure.
     117                 :  */
     118                 : 
     119             186 : static CPLXMLNode *SearchLeafGroupName( CPLXMLNode *psRoot, const char *name )
     120                 : 
     121                 : {
     122             186 :     CPLXMLNode *ret=NULL;
     123                 : 
     124             186 :     if( psRoot == NULL || name == NULL ) return NULL;
     125                 : 
     126                 :     // Has to be a leaf TileGroup with the right name
     127             182 :     if (NULL==SearchXMLSiblings(psRoot->psChild,"TiledGroup"))
     128                 :     {
     129             178 :         if (EQUAL(name,CPLGetXMLValue(psRoot,"Name","")))
     130                 :         {
     131               3 :             return psRoot;
     132                 :         }
     133                 :         else
     134                 :         { // Try a sibling
     135             175 :             return SearchLeafGroupName(psRoot->psNext,name);
     136                 :         }
     137                 :     }
     138                 :     else
     139                 :     { // Is metagroup, try children then siblings
     140               4 :         ret=SearchLeafGroupName(psRoot->psChild,name);
     141               4 :         if (NULL!=ret) return ret;
     142               4 :         return SearchLeafGroupName(psRoot->psNext,name);
     143                 :     }
     144                 : }
     145                 : 
     146                 : /************************************************************************/
     147                 : /*                             BandInterp()                             */
     148                 : /************************************************************************/
     149                 : 
     150                 : /*
     151                 :  * \brief Utility function to calculate color band interpretation.
     152                 :  * Only handles Gray, GrayAlpha, RGB and RGBA, based on total band count
     153                 :  *
     154                 :  * @param nbands is the total number of bands in the image
     155                 :  *
     156                 :  * @param band is the band number, starting with 1
     157                 :  *
     158                 :  * @return GDALColorInterp of the band
     159                 :  */
     160                 : 
     161               4 : static GDALColorInterp BandInterp(int nbands, int band) {
     162               4 :     switch (nbands) {
     163               1 :       case 1: return GCI_GrayIndex;
     164               0 :       case 2: return ((band==1)?GCI_GrayIndex:GCI_AlphaBand);
     165                 :       case 3: // RGB
     166                 :       case 4: // RBGA
     167               3 :         if (band<3)
     168               2 :             return ((band==1)?GCI_RedBand:GCI_GreenBand);
     169               1 :         return ((band==3)?GCI_BlueBand:GCI_AlphaBand);
     170                 :       default:
     171               0 :         return GCI_Undefined;
     172                 :     }
     173                 : }
     174                 : 
     175                 : /************************************************************************/
     176                 : /*                              FindBbox()                              */
     177                 : /************************************************************************/
     178                 : 
     179                 : /*
     180                 :  * \brief Utility function to find the position of the bbox parameter value 
     181                 :  * within a request string.  The search for the bbox is case insensitive
     182                 :  *
     183                 :  * @param in, the string to search into
     184                 :  *
     185                 :  * @return The position from the begining of the string or -1 if not found
     186                 :  */
     187                 : 
     188             355 : static int FindBbox(CPLString in) {
     189                 : 
     190             355 :     size_t pos = in.ifind("&bbox=");
     191             355 :     if (pos == std::string::npos)
     192               0 :         return -1;
     193                 :     else
     194             355 :         return (int)pos + 6;
     195                 : }
     196                 : 
     197                 : /************************************************************************/
     198                 : /*                         FindChangePattern()                          */
     199                 : /************************************************************************/
     200                 : 
     201                 : /*
     202                 :  * \brief Build the right request pattern based on the change request list
     203                 :  * It only gets called on initialization
     204                 :  * @param cdata, possible request strings, white space separated
     205                 :  * @param substs, the list of substitutions to be applied
     206                 :  * @param keys, the list of available substitution keys
     207                 :  * @param ret The return value, a matching request or an empty string
     208                 :  */
     209                 : 
     210              39 : static void FindChangePattern( char *cdata,char **substs, char **keys, CPLString &ret)
     211                 : {
     212                 :     char **papszTokens=CSLTokenizeString2(cdata," \t\n\r",
     213              39 :                                            CSLT_STRIPLEADSPACES|CSLT_STRIPENDSPACES);
     214              39 :     ret.clear();
     215                 : 
     216              39 :     int matchcount=CSLCount(substs);
     217              39 :     int keycount=CSLCount(keys);
     218              39 :     if (keycount<matchcount)
     219                 :     {
     220               0 :         CSLDestroy(papszTokens);
     221               0 :         return;
     222                 :     }
     223                 : 
     224                 :     // A valid string has only the keys in the substs list and none other
     225              39 :     for (int j=0;j<CSLCount(papszTokens);j++)
     226                 :     {
     227              39 :         ret=papszTokens[j];  // The target string
     228              39 :         bool matches=true;
     229                 : 
     230              39 :         for (int k=0;k<keycount;k++)
     231                 :         {
     232               0 :             const char *key=keys[k];
     233               0 :             int sub_number=CSLPartialFindString(substs,key);
     234               0 :             if (sub_number!=-1)
     235                 :             { // It is a listed match
     236                 :                 // But is the match for the key position?
     237               0 :                 char *found_key=NULL;
     238               0 :                 const char *found_value=CPLParseNameValue(substs[sub_number],&found_key);
     239               0 :                 if (found_key!=NULL && EQUAL(found_key,key))
     240                 :                 {  // Should exits in the request
     241               0 :                     if (std::string::npos==ret.find(key))
     242                 :                     {
     243               0 :                         matches=false;
     244               0 :                         break;
     245                 :                     }
     246                 :                     // Execute the substitution on the "ret" string
     247               0 :                     URLSearchAndReplace(&ret,key,found_value);
     248                 :                 }
     249               0 :                 if (found_key!=NULL) CPLFree(found_key);
     250                 :             }
     251                 :             else
     252                 :             {  // Key not in the subst list, should not match
     253               0 :                 if (std::string::npos!=ret.find(key))
     254                 :                 {
     255               0 :                     matches=false;
     256               0 :                     break;
     257                 :                 }
     258                 :             }
     259                 :         } // Key loop
     260              39 :         if (matches)
     261                 :         {
     262              39 :             CSLDestroy(papszTokens);
     263              39 :             return;  // We got the string ready, all keys accounted for and substs applied
     264                 :         }
     265                 :     }
     266               0 :     ret.clear();
     267               0 :     CSLDestroy(papszTokens);
     268                 : }
     269                 : 
     270               3 : GDALWMSMiniDriver_TiledWMS::GDALWMSMiniDriver_TiledWMS() {
     271               3 :     m_requests = NULL;
     272               3 : }
     273                 : 
     274               3 : GDALWMSMiniDriver_TiledWMS::~GDALWMSMiniDriver_TiledWMS() {
     275               3 :     CSLDestroy(m_requests);
     276               3 : }
     277                 : 
     278                 : 
     279                 : // Returns the scale of a WMS request as compared to the base resolution
     280             316 : double GDALWMSMiniDriver_TiledWMS::Scale(const char *request) {
     281             316 :     int bbox=FindBbox(request);
     282             316 :     if (bbox<0) return 0;
     283                 :     double x,y,X,Y;
     284             316 :     sscanf(request+bbox,"%lf,%lf,%lf,%lf",&x,&y,&X,&Y);
     285             316 :     return (m_data_window.m_x1-m_data_window.m_x0)/(X-x)*m_bsx/m_data_window.m_sx;
     286                 : }
     287                 : 
     288                 : 
     289                 : // Finds, extracts, and returns the highest resolution request string from a list, starting at item i
     290              39 : CPLString GDALWMSMiniDriver_TiledWMS::GetLowestScale(char **& list,int i)
     291                 : {
     292              39 :     CPLString req;
     293              39 :     double scale=-1;
     294              39 :     int position=-1;
     295             355 :     while (NULL!=list[i])
     296                 :     {
     297             277 :         double tscale=Scale(list[i]);
     298             277 :         if (tscale>=scale)
     299                 :         {
     300             117 :             scale=tscale;
     301             117 :             position=i;
     302                 :         }
     303             277 :         i++;
     304                 :     }
     305              39 :     if (position>-1)
     306                 :     {
     307              39 :         req=list[position];
     308              39 :         list = CSLRemoveStrings(list,position,1,NULL);
     309                 :     }
     310               0 :     return req;
     311                 : }
     312                 : 
     313                 : /*
     314                 :  *\Brief Initialize minidriver with info from the server
     315                 :  */
     316                 : 
     317               3 : CPLErr GDALWMSMiniDriver_TiledWMS::Initialize(CPLXMLNode *config)
     318                 : {
     319               3 :     CPLErr ret = CE_None;
     320               3 :     CPLXMLNode *tileServiceConfig=NULL;
     321               3 :     CPLHTTPResult *psResult=NULL;
     322               3 :     CPLXMLNode *TG=NULL;
     323                 : 
     324               3 :     char **requests=NULL;
     325               3 :     char **substs=NULL;
     326               3 :     char **keys=NULL;
     327                 : 
     328               3 :     for (int once=1;once;once--) { // Something to break out of
     329                 :         // Parse info from the service
     330                 : 
     331               3 :         m_end_url = CPLGetXMLValue(config,"AdditionalArgs","");
     332               6 :         m_base_url = CPLGetXMLValue(config, "ServerURL", "");
     333               3 :         if (m_base_url.empty()) {
     334               0 :             CPLError(ret=CE_Failure, CPLE_AppDefined, "%s ServerURL missing.",SIG);
     335               0 :             break;
     336                 :         }
     337                 : 
     338               3 :         CPLString tiledGroupName (CPLGetXMLValue(config, "TiledGroupName", ""));
     339               3 :         if (tiledGroupName.empty()) {
     340               0 :             CPLError(ret=CE_Failure, CPLE_AppDefined, "%s TiledGroupName missing.",SIG);
     341                 :             break;
     342                 :         }
     343                 : 
     344                 :         // Change strings, key is an attribute, value is the value of the Change node
     345                 :         // Multiple substitutions are possible
     346               3 :         TG=CPLSearchXMLNode(config, "Change");
     347               3 :         while(TG!=NULL) {
     348               0 :             CPLString name=CPLGetXMLValue(TG,"key","");
     349               0 :             if (name.empty()) {
     350                 :                 CPLError(ret=CE_Failure, CPLE_AppDefined,
     351               0 :                     "%s Change element needs a non-empty \"key\" attribute",SIG);
     352                 :                 break;
     353                 :             }
     354               0 :             substs=CSLSetNameValue(substs,name,CPLGetXMLValue(TG,"",""));
     355               0 :             TG=SearchXMLSiblings(TG,"Change");
     356                 :         }
     357               3 :         if (ret!=CE_None) break;
     358                 : 
     359               3 :         CPLString getTileServiceUrl = m_base_url + "request=GetTileService";
     360               3 :         psResult = CPLHTTPFetch(getTileServiceUrl, NULL);
     361                 : 
     362               3 :         if (NULL==psResult) {
     363               0 :             CPLError(ret=CE_Failure, CPLE_AppDefined, "%s Can't use HTTP", SIG);
     364                 :             break;
     365                 :         }
     366                 : 
     367               3 :         if ((psResult->nStatus!=0)||(NULL==psResult->pabyData)||('\0'==psResult->pabyData[0])) {
     368               0 :             CPLError(ret=CE_Failure, CPLE_AppDefined, "%s Server response error on GetTileService.",SIG);
     369                 :             break;
     370                 :         }
     371                 : 
     372               3 :         if (NULL==(tileServiceConfig=CPLParseXMLString((const char*)psResult->pabyData))) {
     373               0 :             CPLError(ret=CE_Failure,CPLE_AppDefined, "%s Error parsing the GetTileService response.",SIG);
     374                 :             break;
     375                 :         }
     376                 : 
     377               3 :         if (NULL==(TG=CPLSearchXMLNode(tileServiceConfig, "TiledPatterns"))) {
     378                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,
     379               0 :                 "%s Can't locate TiledPatterns in server response.",SIG);
     380                 :             break;
     381                 :         }
     382                 : 
     383                 :         // Get the global base_url and bounding box, these can be overwritten at the tileGroup level
     384                 :         // They are just pointers into existing structures, cleanup is not required
     385               3 :         const char *global_base_url=CPLGetXMLValue(tileServiceConfig,"TiledPatterns.OnlineResource.xlink:href","");
     386               3 :         CPLXMLNode *global_latlonbbox=CPLGetXMLNode(tileServiceConfig, "TiledPatterns.LatLonBoundingBox");
     387               3 :         CPLXMLNode *global_bbox=CPLGetXMLNode(tileServiceConfig, "TiledPatterns.BoundingBox");
     388                 : 
     389               3 :         if (NULL==(TG=SearchLeafGroupName(TG->psChild,tiledGroupName))) {
     390                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,
     391                 :                 "%s Can't locate TiledGroup ""%s"" in server response.",SIG,
     392               0 :                 tiledGroupName.c_str());
     393                 :             break;
     394                 :         }
     395                 : 
     396               3 :         int band_count=atoi(CPLGetXMLValue(TG, "Bands", "3"));
     397                 : 
     398               3 :         if (!GDALCheckBandCount(band_count, FALSE)) {
     399                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG,
     400               0 :                 "Invalid number of bands in server response");
     401                 :             break;
     402                 :         }
     403                 : 
     404                 :         // Collect all keys defined by this tileset
     405               3 :         if (NULL!=CPLGetXMLNode(TG,"Key")) {
     406               0 :             CPLXMLNode *node=CPLGetXMLNode(TG,"Key");
     407               0 :                 while (NULL!=node) {
     408               0 :                     const char *val=CPLGetXMLValue(node,NULL,NULL);
     409               0 :                     if (val) keys=CSLAddString(keys,val);
     410               0 :                     node=SearchXMLSiblings(node,"Key");
     411                 :                 }
     412                 :         }
     413                 : 
     414                 :        // Data values are attributes, they include NoData Min and Max
     415               3 :        if (0!=CPLGetXMLNode(TG,"DataValues")) {
     416               1 :            const char *nodata=CPLGetXMLValue(TG,"DataValues.NoData",NULL);
     417               1 :            if (nodata!=NULL) m_parent_dataset->WMSSetNoDataValue(nodata);
     418               1 :            const char *min=CPLGetXMLValue(TG,"DataValues.min",NULL);
     419               1 :            if (min!=NULL) m_parent_dataset->WMSSetMinValue(min);
     420               1 :            const char *max=CPLGetXMLValue(TG,"DataValues.max",NULL);
     421               1 :            if (max!=NULL) m_parent_dataset->WMSSetMaxValue(max);
     422                 :        }
     423                 : 
     424               3 :         m_parent_dataset->WMSSetBandsCount(band_count);
     425               3 :         m_parent_dataset->WMSSetDataType(GDALGetDataTypeByName(CPLGetXMLValue(TG, "DataType", "Byte")));
     426               3 :         m_projection_wkt=CPLGetXMLValue(TG, "Projection","");
     427                 : 
     428               3 :         m_base_url=CPLGetXMLValue(TG,"OnlineResource.xlink:href",global_base_url);
     429               3 :         if (m_base_url[0]=='\0') {
     430                 :             CPLError(ret=CE_Failure,CPLE_AppDefined, "%s%s",SIG,
     431               0 :                 "Can't locate OnlineResource in the server response.");
     432                 :             break;
     433                 :         }
     434                 : 
     435                 :         // Bounding box, local, global, local lat-lon, global lat-lon, in this order
     436               3 :         CPLXMLNode *bbox = CPLGetXMLNode(TG, "BoundingBox");
     437               3 :         if (NULL==bbox) bbox=global_bbox;
     438               3 :         if (NULL==bbox) bbox=CPLGetXMLNode(TG, "LatLonBoundingBox");
     439               3 :         if (NULL==bbox) bbox=global_latlonbbox;
     440                 : 
     441               3 :         if (NULL==bbox) {
     442                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG,
     443               0 :                 "Can't locate the LatLonBoundingBox in server response.");
     444                 :             break;
     445                 :         }
     446                 : 
     447               3 :         m_data_window.m_x0=atof(CPLGetXMLValue(bbox,"minx","0"));
     448               3 :         m_data_window.m_x1=atof(CPLGetXMLValue(bbox,"maxx","-1"));
     449               3 :         m_data_window.m_y0=atof(CPLGetXMLValue(bbox,"maxy","0"));
     450               3 :         m_data_window.m_y1=atof(CPLGetXMLValue(bbox,"miny","-1"));
     451                 : 
     452               3 :         if ((m_data_window.m_x1-m_data_window.m_x0)<0) {
     453                 :             CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s", SIG,
     454               0 :                 "Coordinate order in BBox, problem in server response");
     455                 :             break;
     456                 :         }
     457                 : 
     458                 :         // Is there a palette?
     459                 :         //
     460                 :         // Format is
     461                 :         // <Palette>
     462                 :         //   <Size>N</Size> : Optional
     463                 :         //   <Model>RGBA|RGB|CMYK|HSV|HLS|L</Model> :mandatory
     464                 :         //   <Entry idx=i c1=v1 c2=v2 c3=v3 c4=v4/> :Optional
     465                 :         //   <Entry .../>
     466                 :         // </Palette>
     467                 :         // the idx attribute is optional, it autoincrements
     468                 :         // The entries are actually vertices, interpolation takes place inside
     469                 :         // The palette starts initialized with zeros
     470                 :         // HSV and HLS are the similar, with c2 and c3 swapped
     471                 :         // RGB or RGBA are same
     472                 :         //
     473                 : 
     474               3 :         GDALColorTable *poColorTable=NULL;
     475                 : 
     476               3 :         if ((band_count==1) && CPLGetXMLNode(TG,"Palette")) {
     477                 : 
     478               1 :             CPLXMLNode *node=CPLGetXMLNode(TG,"Palette");
     479                 : 
     480               1 :             int entries=static_cast<int>(getXMLNum(node,"Size","255"));
     481               1 :             GDALPaletteInterp eInterp=GPI_RGB;
     482                 : 
     483               1 :             CPLString pModel=CPLGetXMLValue(node,"Model","RGB");
     484               1 :             if (!pModel.empty() && pModel.find("RGB")!=std::string::npos)
     485               1 :                 eInterp=GPI_RGB;
     486                 :             else {
     487                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     488                 :                     "%s Palette Model %s is unknown, use RGB or RGBA",
     489               0 :                     SIG, pModel.c_str());
     490               0 :                 return CE_Failure;
     491                 :             }
     492                 : 
     493               2 :             if ((entries>0)&&(entries<257)) {
     494                 :                 int start_idx, end_idx;
     495               1 :                 GDALColorEntry ce_start={0,0,0,255},ce_end={0,0,0,255};
     496                 : 
     497                 :                 // Create it and initialize it to nothing
     498               1 :                 poColorTable = new GDALColorTable(eInterp);
     499               1 :                 poColorTable->CreateColorRamp(0,&ce_start,entries-1,&ce_end);
     500                 :                 // Read the values
     501               1 :                 CPLXMLNode *p=CPLGetXMLNode(node,"Entry");
     502               1 :                 if (p) {
     503                 :                     // Initialize the first entry
     504               1 :                     start_idx=static_cast<int>(getXMLNum(p,"idx","0"));
     505               1 :                     ce_start=GetXMLColorEntry(p);
     506               1 :                     if (start_idx<0) {
     507                 :                         CPLError(CE_Failure, CPLE_AppDefined,
     508               0 :                             "%s Palette index %d not allowed",SIG,start_idx);
     509               0 :                         delete poColorTable;
     510               0 :                         return CE_Failure;
     511                 :                     }
     512               1 :                     poColorTable->SetColorEntry(start_idx,&ce_start);
     513               8 :                     while (NULL!=(p=SearchXMLSiblings(p,"Entry"))) {
     514                 :                         // For every entry, create a ramp
     515               6 :                         ce_end=GetXMLColorEntry(p);
     516               6 :                         end_idx=static_cast<int>(getXMLNum(p,"idx",CPLString().FormatC(start_idx+1).c_str()));
     517               6 :                         if ((end_idx<=start_idx)||(start_idx>=entries)) {
     518                 :                             CPLError(CE_Failure, CPLE_AppDefined,
     519               0 :                                 "%s Index Error at index %d",SIG,end_idx);
     520               0 :                             delete poColorTable;
     521               0 :                             return CE_Failure;
     522                 :                         }
     523                 :                         poColorTable->CreateColorRamp(start_idx,&ce_start,
     524               6 :                             end_idx,&ce_end);
     525               6 :                         ce_start=ce_end;
     526               6 :                         start_idx=end_idx;
     527                 :                     }
     528                 :                 }
     529               1 :                 m_parent_dataset->SetColorTable(poColorTable);
     530                 :             } else {
     531               0 :                 CPLError(CE_Failure, CPLE_AppDefined,"%s Palette definition error",SIG);
     532               0 :                 return CE_Failure;
     533               0 :             }
     534                 :         }
     535                 : 
     536               3 :         int overview_count=0;
     537               3 :         CPLXMLNode *Pattern=TG->psChild;
     538                 : 
     539               3 :         m_bsx=m_bsy=-1;
     540               3 :         m_data_window.m_sx=m_data_window.m_sy=0;
     541                 : 
     542               6 :         for (int once=1;once;once--) { // Something to break out of
     543               3 :             while ((NULL!=Pattern)&&(NULL!=(Pattern=SearchXMLSiblings(Pattern,"=TilePattern")))) {
     544                 :                 int mbsx,mbsy;
     545                 : 
     546              39 :                 CPLString request;
     547              39 :                 FindChangePattern(Pattern->psChild->pszValue,substs,keys,request);
     548                 : 
     549              39 :                 char **papszTokens=CSLTokenizeString2(request,"&",0);
     550                 : 
     551              39 :                 const char* pszWIDTH = CSLFetchNameValue(papszTokens,"WIDTH");
     552              39 :                 const char* pszHEIGHT = CSLFetchNameValue(papszTokens,"HEIGHT");
     553              39 :                 if (pszWIDTH == NULL || pszHEIGHT == NULL)
     554                 :                 {
     555                 :                     CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG,
     556               0 :                         "Cannot find width and/or height parameters.");
     557               0 :                     overview_count=0;
     558               0 :                     CSLDestroy(papszTokens);
     559                 :                     break;
     560                 :                 }
     561                 : 
     562              39 :                 mbsx=atoi(pszWIDTH);
     563              39 :                 mbsy=atoi(pszHEIGHT);
     564              39 :                 if (m_projection_wkt.empty()) {
     565               2 :                     m_projection_wkt = CSLFetchNameValueDef(papszTokens,"SRS", "");
     566               2 :                     if (!m_projection_wkt.empty())
     567               2 :                         m_projection_wkt=ProjToWKT(m_projection_wkt);
     568                 :                 }
     569                 : 
     570              39 :                 if (-1==m_bsx) m_bsx=mbsx;
     571              39 :                 if (-1==m_bsy) m_bsy=mbsy;
     572              39 :                 if ((m_bsy!=mbsy)||(m_bsy!=mbsy)) {
     573                 :                     CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG,
     574               0 :                         "Tileset uses different block sizes.");
     575               0 :                     overview_count=0;
     576               0 :                     CSLDestroy(papszTokens);
     577                 :                     break;
     578                 :                 }
     579                 : 
     580                 :                 double x,y,X,Y;
     581              39 :                 if (sscanf(CSLFetchNameValueDef(papszTokens,"BBOX", ""),"%lf,%lf,%lf,%lf",&x,&y,&X,&Y)!=4)
     582                 :                 {
     583                 :                     CPLError(ret=CE_Failure,CPLE_AppDefined,
     584               0 :                         "%s Error parsing BBOX, pattern %d\n",SIG,overview_count+1);
     585               0 :                     CSLDestroy(papszTokens);
     586                 :                     break;
     587                 :                 }
     588                 :                 // Pick the largest size
     589              39 :                 int sx=static_cast<int>((m_data_window.m_x1-m_data_window.m_x0)/(X-x)*m_bsx);
     590              39 :                 int sy=static_cast<int>(fabs((m_data_window.m_y1-m_data_window.m_y0)/(Y-y)*m_bsy));
     591              39 :                 if (sx>m_data_window.m_sx) m_data_window.m_sx=sx;
     592              39 :                 if (sy>m_data_window.m_sy) m_data_window.m_sy=sy;
     593              39 :                 CSLDestroy(papszTokens);
     594                 : 
     595                 :                 // Only use overlays where the top coordinate is within a pixel from the top of coverage
     596                 :                 double pix_off,temp;
     597              39 :                 pix_off=m_bsy*modf(fabs((Y-m_data_window.m_y0)/(Y-y)),&temp);
     598              78 :                 if ((pix_off<1)||((m_bsy-pix_off)<1)) {
     599              39 :                     requests=CSLAddString(requests,request);
     600              39 :                     overview_count++;
     601                 :                 } else
     602                 :                     CPLError(CE_Warning,CPLE_AppDefined,
     603               0 :                     "%s Overlay size %dX%d can't be used due to alignment",SIG,sx,sy);
     604                 : 
     605              39 :                 Pattern=Pattern->psNext;
     606                 : 
     607                 :             }
     608                 : 
     609                 :             // The tlevel is needed, the tx and ty are not used by this minidriver
     610               3 :             m_data_window.m_tlevel = 0;
     611               3 :             m_data_window.m_tx = 0;
     612               3 :             m_data_window.m_ty = 0;
     613                 : 
     614                 :             // Make sure the parent_dataset values are set before creating the bands
     615               3 :             m_parent_dataset->WMSSetBlockSize(m_bsx,m_bsy);
     616               3 :             m_parent_dataset->WMSSetRasterSize(m_data_window.m_sx,m_data_window.m_sy);
     617                 : 
     618               3 :             m_parent_dataset->WMSSetDataWindow(m_data_window);
     619                 :             //m_parent_dataset->WMSSetOverviewCount(overview_count);
     620               3 :             m_parent_dataset->WMSSetClamp(false);
     621                 : 
     622                 :             // Ready for the Rasterband creation
     623               3 :             for (int i=0;i<overview_count;i++) {
     624              39 :                 CPLString request=GetLowestScale(requests,i);
     625              39 :                 double scale=Scale(request);
     626                 : 
     627                 :                 // Base scale should be very close to 1
     628              39 :                 if ((0==i)&&(fabs(scale-1) > 1e-6)) {
     629                 :                     CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG,
     630               0 :                         "Base resolution pattern missing.");
     631                 :                     break;
     632                 :                 }
     633                 : 
     634                 :                 // Prepare the request and insert it back into the list
     635                 :                 // Find returns an answer relative to the original string start!
     636              39 :                 size_t startBbox=FindBbox(request);
     637              39 :                 size_t endBbox=request.find('&',startBbox);
     638              39 :                 if (endBbox==std::string::npos) endBbox=request.size();
     639              39 :                 request.replace(startBbox,endBbox-startBbox,"${GDAL_BBOX}");
     640              39 :                 requests = CSLInsertString(requests,i,request);
     641                 : 
     642                 :                 // Create the Rasterband or overview
     643             104 :                 for (int j = 1; j <= band_count; j++) {
     644              65 :                     if (i!=0)
     645              60 :                         m_parent_dataset->mGetBand(j)->AddOverview(scale);
     646                 :                     else { // Base resolution
     647                 :                         GDALWMSRasterBand *band=new
     648               5 :                             GDALWMSRasterBand(m_parent_dataset,j,1);
     649               6 :                         if (poColorTable!=NULL) band->SetColorInterpretation(GCI_PaletteIndex);
     650               4 :                         else band->SetColorInterpretation(BandInterp(band_count,j));
     651               5 :                         m_parent_dataset->mSetBand(j, band);
     652                 :                     };
     653                 :                 }
     654                 :             }
     655               3 :             if ((overview_count==0)||(m_bsx<1)||(m_bsy<1)) {
     656                 :                 CPLError(ret=CE_Failure,CPLE_AppDefined,
     657               0 :                     "%s No usable TilePattern elements found",SIG);
     658               0 :                 break;
     659                 :             }
     660                 :         }
     661                 :     }
     662                 : 
     663               3 :     CSLDestroy(keys);
     664               3 :     CSLDestroy(substs);
     665               3 :     if (tileServiceConfig) CPLDestroyXMLNode(tileServiceConfig);
     666               3 :     if (psResult) CPLHTTPDestroyResult(psResult);
     667                 : 
     668               3 :     m_requests=requests;
     669               3 :     return ret;
     670                 : }
     671                 : 
     672               3 : void GDALWMSMiniDriver_TiledWMS::GetCapabilities(GDALWMSMiniDriverCapabilities *caps) {
     673               3 :     caps->m_capabilities_version = 1;
     674               3 :     caps->m_has_arb_overviews = 0;
     675               3 :     caps->m_has_image_request = 1;
     676               3 :     caps->m_has_tiled_image_requeset = 1;
     677               3 :     caps->m_max_overview_count = 32;
     678               3 : }
     679                 : 
     680                 : 
     681                 : // not called
     682               0 : void GDALWMSMiniDriver_TiledWMS::ImageRequest(CPLString *url, const GDALWMSImageRequestInfo &iri) {
     683               0 : }
     684                 : 
     685               2 : void GDALWMSMiniDriver_TiledWMS::TiledImageRequest(CPLString *url, const GDALWMSImageRequestInfo &iri, const GDALWMSTiledImageRequestInfo &tiri) {
     686               2 :     *url = m_base_url;
     687               2 :     URLAppend(url,CSLGetField(m_requests,-tiri.m_level));
     688                 :     URLSearchAndReplace(url,"${GDAL_BBOX}","%013.8f,%013.8f,%013.8f,%013.8f",
     689               2 :                         iri.m_x0,iri.m_y1,iri.m_x1,iri.m_y0);
     690               2 :     URLAppend(url,m_end_url);
     691               2 : }
     692                 : 
     693               3 : const char *GDALWMSMiniDriver_TiledWMS::GetProjectionInWKT() {
     694               3 :     return m_projection_wkt.c_str();
     695                 : }
     696                 : 

Generated by: LCOV version 1.7