LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfsdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 923 758 82.1 %
Date: 2012-12-26 Functions: 36 26 72.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrwfsdatasource.cpp 25182 2012-10-27 12:26:37Z rouault $
       3                 :  *
       4                 :  * Project:  WFS Translator
       5                 :  * Purpose:  Implements OGRWFSDataSource class
       6                 :  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2010, Even Rouault <even dot rouault at mines dash paris dot org>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "cpl_port.h"
      31                 : #include "ogr_wfs.h"
      32                 : #include "ogr_api.h"
      33                 : #include "cpl_minixml.h"
      34                 : #include "cpl_http.h"
      35                 : #include "gmlutils.h"
      36                 : #include "parsexsd.h"
      37                 : #include "swq.h"
      38                 : #include "ogr_p.h"
      39                 : 
      40                 : CPL_CVSID("$Id: ogrwfsdatasource.cpp 25182 2012-10-27 12:26:37Z rouault $");
      41                 : 
      42                 : 
      43                 : /************************************************************************/
      44                 : /*                            WFSFindNode()                             */
      45                 : /************************************************************************/
      46                 : 
      47              43 : CPLXMLNode* WFSFindNode(CPLXMLNode* psXML, const char* pszRootName)
      48                 : {
      49              43 :     CPLXMLNode* psIter = psXML;
      50             119 :     while(psIter)
      51                 :     {
      52              71 :         if (psIter->eType == CXT_Element)
      53                 :         {
      54              68 :             const char* pszNodeName = psIter->pszValue;
      55              68 :             const char* pszSep = strchr(pszNodeName, ':');
      56              68 :             if (pszSep)
      57              24 :                 pszNodeName = pszSep + 1;
      58              68 :             if (EQUAL(pszNodeName, pszRootName))
      59                 :             {
      60              38 :                 return psIter;
      61                 :             }
      62                 :         }
      63              33 :         psIter = psIter->psNext;
      64                 :     }
      65                 : 
      66               5 :     psIter = psXML->psChild;
      67              29 :     while(psIter)
      68                 :     {
      69              22 :         if (psIter->eType == CXT_Element)
      70                 :         {
      71              13 :             const char* pszNodeName = psIter->pszValue;
      72              13 :             const char* pszSep = strchr(pszNodeName, ':');
      73              13 :             if (pszSep)
      74               6 :                 pszNodeName = pszSep + 1;
      75              13 :             if (EQUAL(pszNodeName, pszRootName))
      76                 :             {
      77               3 :                 return psIter;
      78                 :             }
      79                 :         }
      80              19 :         psIter = psIter->psNext;
      81                 :     }
      82               2 :     return NULL;
      83                 : }
      84                 : 
      85                 : /************************************************************************/
      86                 : /*                       OGRWFSWrappedResultLayer                       */
      87                 : /************************************************************************/
      88                 : 
      89                 : class OGRWFSWrappedResultLayer : public OGRLayer
      90                 : {
      91                 :     OGRDataSource *poDS;
      92                 :     OGRLayer      *poLayer;
      93                 : 
      94                 :     public:
      95               1 :         OGRWFSWrappedResultLayer(OGRDataSource* poDS, OGRLayer* poLayer)
      96               1 :         {
      97               1 :             this->poDS = poDS;
      98               1 :             this->poLayer = poLayer;
      99               1 :         }
     100               1 :         ~OGRWFSWrappedResultLayer()
     101               1 :         {
     102               1 :             delete poDS;
     103               1 :         }
     104                 : 
     105               0 :         virtual void        ResetReading() { poLayer->ResetReading(); }
     106               3 :         virtual OGRFeature *GetNextFeature() { return poLayer->GetNextFeature(); }
     107               0 :         virtual OGRErr      SetNextByIndex( long nIndex ) { return poLayer->SetNextByIndex(nIndex); }
     108               0 :         virtual OGRFeature *GetFeature( long nFID ) { return poLayer->GetFeature(nFID); }
     109               0 :         virtual OGRFeatureDefn *GetLayerDefn() { return poLayer->GetLayerDefn(); }
     110               1 :         virtual int         GetFeatureCount( int bForce = TRUE ) { return poLayer->GetFeatureCount(bForce); }
     111               0 :         virtual int         TestCapability( const char * pszCap )  { return poLayer->TestCapability(pszCap); }
     112                 : };
     113                 : 
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                          OGRWFSDataSource()                          */
     117                 : /************************************************************************/
     118                 : 
     119             128 : OGRWFSDataSource::OGRWFSDataSource()
     120                 : 
     121                 : {
     122             128 :     papoLayers = NULL;
     123             128 :     nLayers = 0;
     124                 : 
     125             128 :     pszName = NULL;
     126                 : 
     127             128 :     bUpdate = FALSE;
     128             128 :     bGetFeatureSupportHits = FALSE;
     129             128 :     bNeedNAMESPACE = FALSE;
     130             128 :     bHasMinOperators = FALSE;
     131             128 :     bHasNullCheck = FALSE;
     132             128 :     bPropertyIsNotEqualToSupported = TRUE; /* advertized by deegree but not implemented */
     133             128 :     bTransactionSupport = FALSE;
     134             128 :     papszIdGenMethods = NULL;
     135             128 :     bUseFeatureId = FALSE; /* CubeWerx doesn't like GmlObjectId */
     136             128 :     bGmlObjectIdNeedsGMLPrefix = FALSE;
     137             128 :     bRequiresEnvelopeSpatialFilter = FALSE;
     138                 : 
     139             128 :     bRewriteFile = FALSE;
     140             128 :     psFileXML = NULL;
     141                 : 
     142             128 :     bUseHttp10 = FALSE;
     143             128 :     papszHttpOptions = NULL;
     144                 : 
     145             128 :     bPagingAllowed = CSLTestBoolean(CPLGetConfigOption("OGR_WFS_PAGING_ALLOWED", "OFF"));
     146             128 :     nPageSize = 0;
     147             128 :     if (bPagingAllowed)
     148                 :     {
     149               0 :         nPageSize = atoi(CPLGetConfigOption("OGR_WFS_PAGE_SIZE", "100"));
     150               0 :         if (nPageSize <= 0)
     151               0 :             nPageSize = 100;
     152                 :     }
     153                 : 
     154             128 :     bIsGEOSERVER = FALSE;
     155                 : 
     156             128 :     bLoadMultipleLayerDefn = CSLTestBoolean(CPLGetConfigOption("OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN", "TRUE"));
     157                 : 
     158             128 :     poLayerMetadataDS = NULL;
     159             128 :     poLayerMetadataLayer = NULL;
     160                 : 
     161             128 :     poLayerGetCapabilitiesDS = NULL;
     162             128 :     poLayerGetCapabilitiesLayer = NULL;
     163                 : 
     164             128 :     bKeepLayerNamePrefix = FALSE;
     165             128 : }
     166                 : 
     167                 : /************************************************************************/
     168                 : /*                         ~OGRWFSDataSource()                          */
     169                 : /************************************************************************/
     170                 : 
     171             128 : OGRWFSDataSource::~OGRWFSDataSource()
     172                 : 
     173                 : {
     174             128 :     if (psFileXML)
     175                 :     {
     176               3 :         if (bRewriteFile)
     177                 :         {
     178               1 :             CPLSerializeXMLTreeToFile(psFileXML, pszName);
     179                 :         }
     180                 : 
     181               3 :         CPLDestroyXMLNode(psFileXML);
     182                 :     }
     183                 : 
     184                 :     int i;
     185             498 :     for( i = 0; i < nLayers; i++ )
     186             370 :         delete papoLayers[i];
     187             128 :     CPLFree( papoLayers );
     188                 : 
     189             128 :     if (osLayerMetadataTmpFileName.size() != 0)
     190               1 :         VSIUnlink(osLayerMetadataTmpFileName);
     191             128 :     delete poLayerMetadataDS;
     192             128 :     delete poLayerGetCapabilitiesDS;
     193                 : 
     194             128 :     CPLFree( pszName );
     195             128 :     CSLDestroy( papszIdGenMethods );
     196             128 :     CSLDestroy( papszHttpOptions );
     197             128 : }
     198                 : 
     199                 : /************************************************************************/
     200                 : /*                           TestCapability()                           */
     201                 : /************************************************************************/
     202                 : 
     203               2 : int OGRWFSDataSource::TestCapability( const char * pszCap )
     204                 : 
     205                 : {
     206               2 :     return FALSE;
     207                 : }
     208                 : 
     209                 : /************************************************************************/
     210                 : /*                              GetLayer()                              */
     211                 : /************************************************************************/
     212                 : 
     213              12 : OGRLayer *OGRWFSDataSource::GetLayer( int iLayer )
     214                 : 
     215                 : {
     216              12 :     if( iLayer < 0 || iLayer >= nLayers )
     217               4 :         return NULL;
     218                 :     else
     219               8 :         return papoLayers[iLayer];
     220                 : }
     221                 : 
     222                 : /************************************************************************/
     223                 : /*                          GetLayerByName()                            */
     224                 : /************************************************************************/
     225                 : 
     226             102 : OGRLayer* OGRWFSDataSource::GetLayerByName(const char* pszName)
     227                 : {
     228             102 :     if ( ! pszName )
     229               0 :         return NULL;
     230                 : 
     231             102 :     if (EQUAL(pszName, "WFSLayerMetadata"))
     232                 :     {
     233               1 :         if (osLayerMetadataTmpFileName.size() != 0)
     234               0 :             return poLayerMetadataLayer;
     235                 : 
     236               1 :         osLayerMetadataTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/WFSLayerMetadata.csv", this);
     237               2 :         osLayerMetadataCSV = "layer_name,title,abstract\n" + osLayerMetadataCSV;
     238                 : 
     239                 :         VSIFCloseL(VSIFileFromMemBuffer(osLayerMetadataTmpFileName,
     240                 :                                         (GByte*) osLayerMetadataCSV.c_str(),
     241               1 :                                         osLayerMetadataCSV.size(), FALSE));
     242                 :         poLayerMetadataDS = (OGRDataSource*) OGROpen(osLayerMetadataTmpFileName,
     243               1 :                                                      FALSE, NULL);
     244               1 :         if (poLayerMetadataDS)
     245               1 :             poLayerMetadataLayer = poLayerMetadataDS->GetLayer(0);
     246               1 :         return poLayerMetadataLayer;
     247                 :     }
     248             101 :     else if (EQUAL(pszName, "WFSGetCapabilities"))
     249                 :     {
     250               1 :         if (poLayerGetCapabilitiesLayer != NULL)
     251               0 :             return poLayerGetCapabilitiesLayer;
     252                 : 
     253               1 :         OGRSFDriver* poMEMDrv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
     254               1 :         if (poMEMDrv == NULL)
     255                 :         {
     256               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot load 'Memory' driver");
     257               0 :             return NULL;
     258                 :         }
     259                 : 
     260               1 :         poLayerGetCapabilitiesDS = poMEMDrv->CreateDataSource("WFSGetCapabilities", NULL);
     261               1 :         poLayerGetCapabilitiesLayer = poLayerGetCapabilitiesDS->CreateLayer("WFSGetCapabilities", NULL, wkbNone, NULL);
     262               1 :         OGRFieldDefn oFDefn("content", OFTString);
     263               1 :         poLayerGetCapabilitiesLayer->CreateField(&oFDefn);
     264               1 :         OGRFeature* poFeature = new OGRFeature(poLayerGetCapabilitiesLayer->GetLayerDefn());
     265               2 :         poFeature->SetField(0, osGetCapabilities);
     266               1 :         poLayerGetCapabilitiesLayer->CreateFeature(poFeature);
     267               1 :         delete poFeature;
     268                 : 
     269               1 :         return poLayerGetCapabilitiesLayer;
     270                 :     }
     271                 : 
     272             100 :     int nIndex = GetLayerIndex(pszName);
     273             100 :     if (nIndex < 0)
     274               2 :         return NULL;
     275                 :     else
     276              98 :         return papoLayers[nIndex];
     277                 : }
     278                 : 
     279                 : 
     280                 : /************************************************************************/
     281                 : /*                          GetLayerIndex()                             */
     282                 : /************************************************************************/
     283                 : 
     284             105 : int OGRWFSDataSource::GetLayerIndex(const char* pszName)
     285                 : {
     286                 :     int i;
     287             105 :     int  bHasFoundLayerWithColon = FALSE;
     288                 : 
     289                 :     /* first a case sensitive check */
     290            1067 :     for( i = 0; i < nLayers; i++ )
     291                 :     {
     292            1015 :         OGRWFSLayer *poLayer = papoLayers[i];
     293                 : 
     294            1015 :         if( strcmp( pszName, poLayer->GetName() ) == 0 )
     295              53 :             return i;
     296                 : 
     297             962 :         bHasFoundLayerWithColon |= (strchr( poLayer->GetName(), ':') != NULL);
     298                 :     }
     299                 : 
     300                 :     /* then case insensitive */
     301             922 :     for( i = 0; i < nLayers; i++ )
     302                 :     {
     303             870 :         OGRWFSLayer *poLayer = papoLayers[i];
     304                 : 
     305             870 :         if( EQUAL( pszName, poLayer->GetName() ) )
     306               0 :             return i;
     307                 :     }
     308                 : 
     309                 :     /* now try looking after the colon character */
     310              52 :     if (!bKeepLayerNamePrefix && bHasFoundLayerWithColon && strchr(pszName, ':') == NULL)
     311                 :     {
     312             424 :         for( i = 0; i < nLayers; i++ )
     313                 :         {
     314             424 :             OGRWFSLayer *poLayer = papoLayers[i];
     315                 : 
     316             424 :             const char* pszAfterColon = strchr( poLayer->GetName(), ':');
     317             424 :             if( pszAfterColon && EQUAL( pszName, pszAfterColon + 1 ) )
     318              50 :                 return i;
     319                 :         }
     320                 :     }
     321                 : 
     322               2 :     return -1;
     323                 : }
     324                 : 
     325                 : /************************************************************************/
     326                 : /*                    FindSubStringInsensitive()                        */
     327                 : /************************************************************************/
     328                 : 
     329             155 : const char* FindSubStringInsensitive(const char* pszStr,
     330                 :                                      const char* pszSubStr)
     331                 : {
     332             155 :     size_t nSubStrPos = CPLString(pszStr).ifind(pszSubStr);
     333             155 :     if (nSubStrPos == std::string::npos)
     334             154 :         return NULL;
     335               1 :     return pszStr + nSubStrPos;
     336                 : }
     337                 : 
     338                 : /************************************************************************/
     339                 : /*                 DetectIfGetFeatureSupportHits()                      */
     340                 : /************************************************************************/
     341                 : 
     342              15 : static int DetectIfGetFeatureSupportHits(CPLXMLNode* psRoot)
     343                 : {
     344                 :     CPLXMLNode* psOperationsMetadata =
     345              15 :         CPLGetXMLNode(psRoot, "OperationsMetadata");
     346              15 :     if (!psOperationsMetadata)
     347                 :     {
     348               0 :         CPLDebug("WFS", "Could not find <OperationsMetadata>");
     349               0 :         return FALSE;
     350                 :     }
     351                 : 
     352              15 :     CPLXMLNode* psChild = psOperationsMetadata->psChild;
     353              57 :     while(psChild)
     354                 :     {
     355              42 :         if (psChild->eType == CXT_Element &&
     356                 :             strcmp(psChild->pszValue, "Operation") == 0 &&
     357                 :             strcmp(CPLGetXMLValue(psChild, "name", ""), "GetFeature") == 0)
     358                 :         {
     359              15 :             break;
     360                 :         }
     361              27 :         psChild = psChild->psNext;
     362                 :     }
     363              15 :     if (!psChild)
     364                 :     {
     365               0 :         CPLDebug("WFS", "Could not find <Operation name=\"GetFeature\">");
     366               0 :         return FALSE;
     367                 :     }
     368                 : 
     369              15 :     psChild = psChild->psChild;
     370              62 :     while(psChild)
     371                 :     {
     372              41 :         if (psChild->eType == CXT_Element &&
     373                 :             strcmp(psChild->pszValue, "Parameter") == 0 &&
     374                 :             strcmp(CPLGetXMLValue(psChild, "name", ""), "resultType") == 0)
     375                 :         {
     376               9 :             break;
     377                 :         }
     378              32 :         psChild = psChild->psNext;
     379                 :     }
     380              15 :    if (!psChild)
     381                 :     {
     382               6 :         CPLDebug("WFS", "Could not find <Parameter name=\"resultType\">");
     383               6 :         return FALSE;
     384                 :     }
     385                 : 
     386               9 :     psChild = psChild->psChild;
     387              36 :     while(psChild)
     388                 :     {
     389              25 :         if (psChild->eType == CXT_Element &&
     390                 :             strcmp(psChild->pszValue, "Value") == 0)
     391                 :         {
     392              16 :             CPLXMLNode* psChild2 = psChild->psChild;
     393              41 :             while(psChild2)
     394                 :             {
     395              16 :                 if (psChild2->eType == CXT_Text &&
     396                 :                     strcmp(psChild2->pszValue, "hits") == 0)
     397                 :                 {
     398               7 :                     CPLDebug("WFS", "GetFeature operation supports hits");
     399               7 :                     return TRUE;
     400                 :                 }
     401               9 :                 psChild2 = psChild2->psNext;
     402                 :             }
     403                 :         }
     404              18 :         psChild = psChild->psNext;
     405                 :     }
     406                 : 
     407               2 :     return FALSE;
     408                 : }
     409                 : 
     410                 : /************************************************************************/
     411                 : /*                   DetectRequiresEnvelopeSpatialFilter()              */
     412                 : /************************************************************************/
     413                 : 
     414              21 : int OGRWFSDataSource::DetectRequiresEnvelopeSpatialFilter(CPLXMLNode* psRoot)
     415                 : {
     416                 :     /* This is a heuristic to detect Deegree 3 servers, such as */
     417                 :     /* http://deegree3-demo.deegree.org:80/deegree-utah-demo/services */
     418                 :     /* that are very GML3 strict, and don't like <gml:Box> in a <Filter><BBOX> */
     419                 :     /* request, but requires instead <gml:Envelope>, but some servers (such as MapServer) */
     420                 :     /* don't like <gml:Envelope> so we are obliged to detect the kind of server */
     421                 : 
     422                 :     int nCount;
     423                 :     CPLXMLNode* psChild;
     424                 : 
     425                 :     CPLXMLNode* psGeometryOperands =
     426              21 :         CPLGetXMLNode(psRoot, "Filter_Capabilities.Spatial_Capabilities.GeometryOperands");
     427              21 :     if (!psGeometryOperands)
     428                 :     {
     429               0 :         return FALSE;
     430                 :     }
     431                 : 
     432              21 :     nCount = 0;
     433              21 :     psChild = psGeometryOperands->psChild;
     434             187 :     while(psChild)
     435                 :     {
     436             145 :         nCount ++;
     437             145 :         psChild = psChild->psNext;
     438                 :     }
     439                 :     /* Magic number... Might be fragile */
     440              21 :     return (nCount == 19);
     441                 : }
     442                 : 
     443                 : /************************************************************************/
     444                 : /*                       GetPostTransactionURL()                        */
     445                 : /************************************************************************/
     446                 : 
     447               5 : CPLString OGRWFSDataSource::GetPostTransactionURL()
     448                 : {
     449               5 :     if (osPostTransactionURL.size())
     450               5 :         return osPostTransactionURL;
     451                 : 
     452               0 :     osPostTransactionURL = osBaseURL;
     453               0 :     const char* pszPostTransactionURL = osPostTransactionURL.c_str();
     454               0 :     const char* pszEsperluet = strchr(pszPostTransactionURL, '?');
     455               0 :     if (pszEsperluet)
     456               0 :         osPostTransactionURL.resize(pszEsperluet - pszPostTransactionURL);
     457                 : 
     458               0 :     return osPostTransactionURL;
     459                 : }
     460                 : 
     461                 : /************************************************************************/
     462                 : /*                    DetectTransactionSupport()                        */
     463                 : /************************************************************************/
     464                 : 
     465              22 : int OGRWFSDataSource::DetectTransactionSupport(CPLXMLNode* psRoot)
     466                 : {
     467                 :     CPLXMLNode* psTransactionWFS100 =
     468              22 :         CPLGetXMLNode(psRoot, "Capability.Request.Transaction");
     469              22 :     if (psTransactionWFS100)
     470                 :     {
     471               1 :         CPLXMLNode* psPostURL = CPLGetXMLNode(psTransactionWFS100, "DCPType.HTTP.Post");
     472               1 :         if (psPostURL)
     473                 :         {
     474               0 :             const char* pszPOSTURL = CPLGetXMLValue(psPostURL, "onlineResource", NULL);
     475               0 :             if (pszPOSTURL)
     476                 :             {
     477               0 :                 osPostTransactionURL = pszPOSTURL;
     478                 :             }
     479                 :         }
     480                 : 
     481               1 :         bTransactionSupport = TRUE;
     482               1 :         return TRUE;
     483                 :     }
     484                 :     
     485                 :     CPLXMLNode* psOperationsMetadata =
     486              21 :         CPLGetXMLNode(psRoot, "OperationsMetadata");
     487              21 :     if (!psOperationsMetadata)
     488                 :     {
     489               0 :         return FALSE;
     490                 :     }
     491                 : 
     492              21 :     CPLXMLNode* psChild = psOperationsMetadata->psChild;
     493             203 :     while(psChild)
     494                 :     {
     495             177 :         if (psChild->eType == CXT_Element &&
     496                 :             strcmp(psChild->pszValue, "Operation") == 0 &&
     497                 :             strcmp(CPLGetXMLValue(psChild, "name", ""), "Transaction") == 0)
     498                 :         {
     499              16 :             break;
     500                 :         }
     501             161 :         psChild = psChild->psNext;
     502                 :     }
     503              21 :     if (!psChild)
     504                 :     {
     505               5 :         CPLDebug("WFS", "No transaction support");
     506               5 :         return FALSE;
     507                 :     }
     508                 : 
     509              16 :     bTransactionSupport = TRUE;
     510              16 :     CPLDebug("WFS", "Transaction support !");
     511                 : 
     512                 : 
     513              16 :     CPLXMLNode* psPostURL = CPLGetXMLNode(psChild, "DCP.HTTP.Post");
     514              16 :     if (psPostURL)
     515                 :     {
     516              15 :         const char* pszPOSTURL = CPLGetXMLValue(psPostURL, "href", NULL);
     517              15 :         if (pszPOSTURL)
     518              15 :             osPostTransactionURL = pszPOSTURL;
     519                 :     }
     520                 : 
     521              16 :     psChild = psChild->psChild;
     522              85 :     while(psChild)
     523                 :     {
     524              65 :         if (psChild->eType == CXT_Element &&
     525                 :             strcmp(psChild->pszValue, "Parameter") == 0 &&
     526                 :             strcmp(CPLGetXMLValue(psChild, "name", ""), "idgen") == 0)
     527                 :         {
     528              12 :             break;
     529                 :         }
     530              53 :         psChild = psChild->psNext;
     531                 :     }
     532              16 :    if (!psChild)
     533                 :     {
     534               4 :         papszIdGenMethods = CSLAddString(NULL, "GenerateNew");
     535               4 :         return TRUE;
     536                 :     }
     537                 : 
     538              12 :     psChild = psChild->psChild;
     539              65 :     while(psChild)
     540                 :     {
     541              41 :         if (psChild->eType == CXT_Element &&
     542                 :             strcmp(psChild->pszValue, "Value") == 0)
     543                 :         {
     544              29 :             CPLXMLNode* psChild2 = psChild->psChild;
     545              87 :             while(psChild2)
     546                 :             {
     547              29 :                 if (psChild2->eType == CXT_Text)
     548                 :                 {
     549                 :                     papszIdGenMethods = CSLAddString(papszIdGenMethods,
     550              29 :                                                      psChild2->pszValue);
     551                 :                 }
     552              29 :                 psChild2 = psChild2->psNext;
     553                 :             }
     554                 :         }
     555              41 :         psChild = psChild->psNext;
     556                 :     }
     557                 : 
     558              12 :     return TRUE;
     559                 : }
     560                 : 
     561                 : /************************************************************************/
     562                 : /*                      FindComparisonOperator()                        */
     563                 : /************************************************************************/
     564                 : 
     565             178 : static int FindComparisonOperator(CPLXMLNode* psNode, const char* pszVal)
     566                 : {
     567             178 :     CPLXMLNode* psChild = psNode->psChild;
     568            1085 :     while(psChild)
     569                 :     {
     570             895 :         if (psChild->eType == CXT_Element &&
     571                 :             strcmp(psChild->pszValue, "ComparisonOperator") == 0)
     572                 :         {
     573             887 :             if (strcmp(CPLGetXMLValue(psChild, NULL, ""), pszVal) == 0)
     574             118 :                 return TRUE;
     575                 : 
     576                 :             /* For WFS 2.0.0 */
     577             769 :             const char* pszName = CPLGetXMLValue(psChild, "name", NULL);
     578             769 :             if (pszName != NULL && strncmp(pszName, "PropertyIs", 10) == 0 &&
     579                 :                 strcmp(pszName + 10, pszVal) == 0)
     580              48 :                 return TRUE;
     581                 :         }
     582             729 :         psChild = psChild->psNext;
     583                 :     }
     584              12 :     return FALSE;
     585                 : }
     586                 : 
     587                 : /************************************************************************/
     588                 : /*                          LoadFromFile()                              */
     589                 : /************************************************************************/
     590                 : 
     591             129 : CPLXMLNode* OGRWFSDataSource::LoadFromFile( const char * pszFilename )
     592                 : {
     593                 :     VSILFILE *fp;
     594                 :     char achHeader[1024];
     595                 : 
     596                 :     VSIStatBufL sStatBuf;
     597             129 :     if (VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) != 0 ||
     598                 :         VSI_ISDIR(sStatBuf.st_mode))
     599              57 :         return NULL;
     600                 : 
     601              72 :     fp = VSIFOpenL( pszFilename, "rb" );
     602                 : 
     603              72 :     if( fp == NULL )
     604               0 :         return NULL;
     605                 : 
     606                 :     int nRead;
     607              72 :     if( (nRead = VSIFReadL( achHeader, 1, sizeof(achHeader) - 1, fp )) == 0 )
     608                 :     {
     609               0 :         VSIFCloseL( fp );
     610               0 :         return NULL;
     611                 :     }
     612              72 :     achHeader[nRead] = 0;
     613                 : 
     614              72 :     if( !EQUALN(achHeader,"<OGRWFSDataSource>",18) &&
     615                 :         strstr(achHeader,"<WFS_Capabilities") == NULL &&
     616                 :         strstr(achHeader,"<wfs:WFS_Capabilities") == NULL)
     617                 :     {
     618              67 :         VSIFCloseL( fp );
     619              67 :         return NULL;
     620                 :     }
     621                 : 
     622                 : /* -------------------------------------------------------------------- */
     623                 : /*      It is the right file, now load the full XML definition.         */
     624                 : /* -------------------------------------------------------------------- */
     625                 :     int nLen;
     626                 : 
     627               5 :     VSIFSeekL( fp, 0, SEEK_END );
     628               5 :     nLen = (int) VSIFTellL( fp );
     629               5 :     VSIFSeekL( fp, 0, SEEK_SET );
     630                 : 
     631               5 :     char* pszXML = (char *) VSIMalloc(nLen+1);
     632               5 :     if (pszXML == NULL)
     633                 :     {
     634               0 :         VSIFCloseL( fp );
     635               0 :         return NULL;
     636                 :     }
     637               5 :     pszXML[nLen] = '\0';
     638               5 :     if( ((int) VSIFReadL( pszXML, 1, nLen, fp )) != nLen )
     639                 :     {
     640               0 :         CPLFree( pszXML );
     641               0 :         VSIFCloseL( fp );
     642                 : 
     643               0 :         return NULL;
     644                 :     }
     645               5 :     VSIFCloseL( fp );
     646                 : 
     647               5 :     if (strstr(pszXML, "CubeWerx"))
     648                 :     {
     649                 :         /* At least true for CubeWerx Suite 4.15.1 */
     650               0 :         bUseFeatureId = TRUE;
     651                 :     }
     652               5 :     else if (strstr(pszXML, "deegree"))
     653                 :     {
     654               0 :         bGmlObjectIdNeedsGMLPrefix = TRUE;
     655                 :     }
     656                 : 
     657               5 :     CPLXMLNode* psXML = CPLParseXMLString( pszXML );
     658               5 :     CPLFree( pszXML );
     659                 : 
     660               5 :     return psXML;
     661                 : }
     662                 : 
     663                 : /************************************************************************/
     664                 : /*                          SendGetCapabilities()                       */
     665                 : /************************************************************************/
     666                 : 
     667              19 : CPLHTTPResult* OGRWFSDataSource::SendGetCapabilities(const char* pszBaseURL,
     668                 :                                                      CPLString& osTypeName)
     669                 : {
     670              19 :     CPLString osURL(pszBaseURL);
     671                 : 
     672              19 :     osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
     673              19 :     osURL = CPLURLAddKVP(osURL, "REQUEST", "GetCapabilities");
     674              19 :     osTypeName = CPLURLGetValue(osURL, "TYPENAME");
     675              19 :     osURL = CPLURLAddKVP(osURL, "TYPENAME", NULL);
     676              19 :     osURL = CPLURLAddKVP(osURL, "FILTER", NULL);
     677              19 :     osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", NULL);
     678              19 :     osURL = CPLURLAddKVP(osURL, "MAXFEATURES", NULL);
     679              19 :     osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", NULL);
     680                 : 
     681                 :     CPLHTTPResult* psResult;
     682                 : 
     683              19 :     CPLDebug("WFS", "%s", osURL.c_str());
     684                 : 
     685              19 :     psResult = HTTPFetch( osURL, NULL);
     686              19 :     if (psResult == NULL)
     687                 :     {
     688               0 :         return NULL;
     689                 :     }
     690                 : 
     691              19 :     if (strstr((const char*)psResult->pabyData,
     692                 :                                     "<ServiceExceptionReport") != NULL ||
     693                 :         strstr((const char*)psResult->pabyData,
     694                 :                                     "<ows:ExceptionReport") != NULL ||
     695                 :         strstr((const char*)psResult->pabyData,
     696                 :                                     "<ExceptionReport") != NULL)
     697                 :     {
     698                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
     699               0 :                 psResult->pabyData);
     700               0 :         CPLHTTPDestroyResult(psResult);
     701               0 :         return NULL;
     702                 :     }
     703                 : 
     704              19 :     return psResult;
     705                 : }
     706                 : 
     707                 : /************************************************************************/
     708                 : /*                                Open()                                */
     709                 : /************************************************************************/
     710                 : 
     711             129 : int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
     712                 : 
     713                 : {
     714             129 :     bUpdate = bUpdateIn;
     715             129 :     CPLFree(pszName);
     716             129 :     pszName = CPLStrdup(pszFilename);
     717                 : 
     718             129 :     CPLXMLNode* psWFSCapabilities = NULL;
     719             129 :     CPLXMLNode* psXML = LoadFromFile(pszFilename);
     720             129 :     CPLString osTypeName;
     721             129 :     const char* pszBaseURL = NULL;
     722                 : 
     723             129 :     if (psXML == NULL)
     724                 :     {
     725             124 :         if (!EQUALN(pszFilename, "WFS:", 4) &&
     726                 :             FindSubStringInsensitive(pszFilename, "SERVICE=WFS") == NULL)
     727                 :         {
     728             106 :             return FALSE;
     729                 :         }
     730                 : 
     731              18 :         pszBaseURL = pszFilename;
     732              18 :         if (EQUALN(pszFilename, "WFS:", 4))
     733              18 :             pszBaseURL += 4;
     734                 : 
     735              18 :         osBaseURL = pszBaseURL;
     736                 : 
     737              18 :         if (strncmp(pszBaseURL, "http://", 7) != 0 &&
     738                 :             strncmp(pszBaseURL, "https://", 8) != 0)
     739               0 :             return FALSE;
     740                 : 
     741                 :         CPLHTTPResult* psResult = SendGetCapabilities(pszBaseURL,
     742              18 :                                                       osTypeName);
     743              18 :         if (psResult == NULL)
     744                 :         {
     745               0 :             return FALSE;
     746                 :         }
     747                 : 
     748              18 :         if (strstr((const char*) psResult->pabyData, "CubeWerx"))
     749                 :         {
     750                 :             /* At least true for CubeWerx Suite 4.15.1 */
     751               0 :             bUseFeatureId = TRUE;
     752                 :         }
     753              18 :         else if (strstr((const char*) psResult->pabyData, "deegree"))
     754                 :         {
     755               9 :             bGmlObjectIdNeedsGMLPrefix = TRUE;
     756                 :         }
     757                 : 
     758              18 :         psXML = CPLParseXMLString( (const char*) psResult->pabyData );
     759              18 :         if (psXML == NULL)
     760                 :         {
     761                 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
     762               0 :                     psResult->pabyData);
     763               0 :             CPLHTTPDestroyResult(psResult);
     764               0 :             return FALSE;
     765                 :         }
     766              18 :         osGetCapabilities = (const char*) psResult->pabyData;
     767                 : 
     768              18 :         CPLHTTPDestroyResult(psResult);
     769                 :     }
     770               5 :     else if ( WFSFindNode( psXML, "OGRWFSDataSource" ) == NULL &&
     771                 :               WFSFindNode( psXML, "WFS_Capabilities" ) != NULL )
     772                 :     {
     773                 :         /* This is directly the Capabilities document */
     774               1 :         char* pszXML = CPLSerializeXMLTree(WFSFindNode( psXML, "WFS_Capabilities" ));
     775               1 :         osGetCapabilities = pszXML;
     776               1 :         CPLFree(pszXML);
     777                 :     }
     778                 :     else
     779                 :     {
     780               4 :         CPLXMLNode* psRoot = WFSFindNode( psXML, "OGRWFSDataSource" );
     781               4 :         if (psRoot == NULL)
     782                 :         {
     783                 :             CPLError(CE_Failure, CPLE_AppDefined,
     784               0 :                      "Cannot find <OGRWFSDataSource>");
     785               0 :             CPLDestroyXMLNode( psXML );
     786               0 :             return FALSE;
     787                 :         }
     788                 : 
     789               4 :         pszBaseURL = CPLGetXMLValue(psRoot, "URL", NULL);
     790               4 :         if (pszBaseURL == NULL)
     791                 :         {
     792                 :             CPLError(CE_Failure, CPLE_AppDefined,
     793               0 :                      "Cannot find <URL>");
     794               0 :             CPLDestroyXMLNode( psXML );
     795               0 :             return FALSE;
     796                 :         }
     797               4 :         osBaseURL = pszBaseURL;
     798                 : 
     799                 : /* -------------------------------------------------------------------- */
     800                 : /*      Capture other parameters.                                       */
     801                 : /* -------------------------------------------------------------------- */
     802                 :         const char  *pszParm;
     803                 : 
     804               4 :         pszParm = CPLGetXMLValue( psRoot, "Timeout", NULL );
     805               4 :         if( pszParm )
     806                 :             papszHttpOptions =
     807                 :                 CSLSetNameValue(papszHttpOptions,
     808               0 :                                 "TIMEOUT", pszParm );
     809                 : 
     810               4 :         pszParm = CPLGetXMLValue( psRoot, "HTTPAUTH", NULL );
     811               4 :         if( pszParm )
     812                 :             papszHttpOptions =
     813                 :                 CSLSetNameValue( papszHttpOptions,
     814               0 :                                 "HTTPAUTH", pszParm );
     815                 : 
     816               4 :         pszParm = CPLGetXMLValue( psRoot, "USERPWD", NULL );
     817               4 :         if( pszParm )
     818                 :             papszHttpOptions =
     819                 :                 CSLSetNameValue( papszHttpOptions,
     820               0 :                                 "USERPWD", pszParm );
     821                 : 
     822               4 :         pszParm = CPLGetXMLValue( psRoot, "Version", NULL );
     823               4 :         if( pszParm )
     824               0 :             osVersion = pszParm;
     825                 : 
     826               4 :         pszParm = CPLGetXMLValue( psRoot, "PagingAllowed", NULL );
     827               4 :         if( pszParm )
     828               0 :             bPagingAllowed = CSLTestBoolean(pszParm);
     829                 : 
     830               4 :         pszParm = CPLGetXMLValue( psRoot, "PageSize", NULL );
     831               4 :         if( pszParm )
     832                 :         {
     833               0 :             nPageSize = atoi(pszParm);
     834               0 :             if (nPageSize <= 0)
     835               0 :                 nPageSize = 100;
     836                 :         }
     837                 : 
     838               4 :         osTypeName = CPLURLGetValue(pszBaseURL, "TYPENAME");
     839                 : 
     840               4 :         psWFSCapabilities = WFSFindNode( psRoot, "WFS_Capabilities" );
     841               4 :         if (psWFSCapabilities == NULL)
     842                 :         {
     843                 :             CPLHTTPResult* psResult = SendGetCapabilities(pszBaseURL,
     844               1 :                                                           osTypeName);
     845               1 :             if (psResult == NULL)
     846                 :             {
     847               0 :                 CPLDestroyXMLNode( psXML );
     848               0 :                 return FALSE;
     849                 :             }
     850                 : 
     851               1 :             CPLXMLNode* psXML2 = CPLParseXMLString( (const char*) psResult->pabyData );
     852               1 :             if (psXML2 == NULL)
     853                 :             {
     854                 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
     855               0 :                     psResult->pabyData);
     856               0 :                 CPLHTTPDestroyResult(psResult);
     857               0 :                 CPLDestroyXMLNode( psXML );
     858               0 :                 return FALSE;
     859                 :             }
     860                 : 
     861               1 :             CPLHTTPDestroyResult(psResult);
     862                 : 
     863               1 :             psWFSCapabilities = WFSFindNode( psXML2, "WFS_Capabilities" );
     864               1 :             if (psWFSCapabilities == NULL )
     865                 :             {
     866                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     867               0 :                     "Cannot find <WFS_Capabilities>");
     868               0 :                 CPLDestroyXMLNode( psXML );
     869               0 :                 CPLDestroyXMLNode( psXML2 );
     870               0 :                 return FALSE;
     871                 :             }
     872                 : 
     873               1 :             CPLAddXMLChild(psXML, CPLCloneXMLTree(psWFSCapabilities));
     874                 : 
     875               1 :             int bOK = CPLSerializeXMLTreeToFile(psXML, pszFilename);
     876                 :             
     877               1 :             CPLDestroyXMLNode( psXML );
     878               1 :             CPLDestroyXMLNode( psXML2 );
     879                 : 
     880               1 :             if (bOK)
     881               1 :                 return Open(pszFilename, bUpdate);
     882                 :             else
     883               0 :                 return FALSE;
     884                 :         }
     885                 :         else
     886                 :         {
     887               3 :             psFileXML = psXML;
     888                 : 
     889                 :             /* To avoid to have nodes after WFSCapabilities */
     890               3 :             CPLXMLNode* psAfterWFSCapabilities = psWFSCapabilities->psNext;
     891               3 :             psWFSCapabilities->psNext = NULL;
     892               3 :             char* pszXML = CPLSerializeXMLTree(psWFSCapabilities);
     893               3 :             psWFSCapabilities->psNext = psAfterWFSCapabilities;
     894               3 :             osGetCapabilities = pszXML;
     895               3 :             CPLFree(pszXML);
     896                 :         }
     897                 :     }
     898                 : 
     899                 :     int bInvertAxisOrderIfLatLong = CSLTestBoolean(CPLGetConfigOption(
     900              22 :                                   "GML_INVERT_AXIS_ORDER_IF_LAT_LONG", "YES"));
     901                 : 
     902              22 :     CPLXMLNode* psStrippedXML = CPLCloneXMLTree(psXML);
     903              22 :     CPLStripXMLNamespace( psStrippedXML, NULL, TRUE );
     904              22 :     psWFSCapabilities = CPLGetXMLNode( psStrippedXML, "=WFS_Capabilities" );
     905              22 :     if (psWFSCapabilities == NULL)
     906                 :     {
     907               3 :         psWFSCapabilities = CPLGetXMLNode( psStrippedXML, "=OGRWFSDataSource.WFS_Capabilities" );
     908                 :     }
     909              22 :     if (psWFSCapabilities == NULL)
     910                 :     {
     911                 :         CPLError(CE_Failure, CPLE_AppDefined,
     912               0 :                     "Cannot find <WFS_Capabilities>");
     913               0 :         if (!psFileXML) CPLDestroyXMLNode( psXML );
     914               0 :         CPLDestroyXMLNode( psStrippedXML );
     915               0 :         return FALSE;
     916                 :     }
     917                 : 
     918              22 :     if (pszBaseURL == NULL)
     919                 :     {
     920                 :         /* This is directly the Capabilities document */
     921               1 :         pszBaseURL = CPLGetXMLValue( psWFSCapabilities, "OperationsMetadata.Operation.DCP.HTTP.Get.href", NULL );
     922               1 :         if (pszBaseURL == NULL) /* WFS 1.0.0 variant */
     923               0 :             pszBaseURL = CPLGetXMLValue( psWFSCapabilities, "Capability.Request.GetCapabilities.DCPType.HTTP.Get.onlineResource", NULL );
     924                 : 
     925               1 :         if (pszBaseURL == NULL)
     926                 :         {
     927                 :             CPLError(CE_Failure, CPLE_AppDefined,
     928               0 :                         "Cannot find base URL");
     929               0 :             CPLDestroyXMLNode( psStrippedXML );
     930               0 :             return FALSE;
     931                 :         }
     932                 : 
     933               1 :         osBaseURL = pszBaseURL;
     934                 :     }
     935                 : 
     936              22 :     if (osVersion.size() == 0)
     937              22 :         osVersion = CPLGetXMLValue(psWFSCapabilities, "version", "1.0.0");
     938              22 :     if (strcmp(osVersion.c_str(), "1.0.0") == 0)
     939               1 :         bUseFeatureId = TRUE;
     940                 :     else
     941                 :     {
     942                 :         /* Some servers happen to support RESULTTYPE=hits in 1.0.0, but there */
     943                 :         /* is no way to advertisze this */
     944              21 :         if (atoi(osVersion) >= 2)
     945               6 :             bGetFeatureSupportHits = TRUE;  /* WFS >= 2.0.0 supports hits */
     946                 :         else
     947              15 :             bGetFeatureSupportHits = DetectIfGetFeatureSupportHits(psWFSCapabilities);
     948              21 :         bRequiresEnvelopeSpatialFilter = DetectRequiresEnvelopeSpatialFilter(psWFSCapabilities);
     949                 :     }
     950                 : 
     951              22 :     DetectTransactionSupport(psWFSCapabilities);
     952                 : 
     953                 :     /* Detect if server is GEOSERVER */
     954              22 :     CPLXMLNode* psKeywords = CPLGetXMLNode(psWFSCapabilities, "ServiceIdentification.Keywords");
     955              22 :     if (psKeywords)
     956                 :     {
     957               6 :         CPLXMLNode* psKeyword = psKeywords->psChild;
     958              36 :         for(;psKeyword != NULL;psKeyword=psKeyword->psNext)
     959                 :         {
     960              30 :             if (psKeyword->eType == CXT_Element &&
     961                 :                 psKeyword->pszValue != NULL &&
     962                 :                 EQUAL(psKeyword->pszValue, "Keyword") &&
     963                 :                 psKeyword->psChild != NULL &&
     964                 :                 psKeyword->psChild->pszValue != NULL &&
     965                 :                 EQUALN(psKeyword->psChild->pszValue, "GEOSERVER", 9))
     966                 :             {
     967               0 :                 bIsGEOSERVER = TRUE;
     968               0 :                 break;
     969                 :             }
     970                 :         }
     971                 :     }
     972                 : 
     973              22 :     if (bUpdate && !bTransactionSupport)
     974                 :     {
     975                 :         CPLError(CE_Failure, CPLE_AppDefined,
     976               0 :                     "Server is read-only WFS; no WFS-T feature advertized");
     977               0 :         if (!psFileXML) CPLDestroyXMLNode( psXML );
     978               0 :         CPLDestroyXMLNode( psStrippedXML );
     979               0 :         return FALSE;
     980                 :     }
     981                 : 
     982              22 :     CPLXMLNode* psFilterCap = CPLGetXMLNode(psWFSCapabilities, "Filter_Capabilities.Scalar_Capabilities");
     983              22 :     if (psFilterCap)
     984                 :     {
     985                 :         bHasMinOperators = CPLGetXMLNode(psFilterCap, "LogicalOperators") != NULL ||
     986              22 :                            CPLGetXMLNode(psFilterCap, "Logical_Operators") != NULL;
     987              22 :         if (CPLGetXMLNode(psFilterCap, "ComparisonOperators"))
     988              21 :             psFilterCap = CPLGetXMLNode(psFilterCap, "ComparisonOperators");
     989               1 :         else if (CPLGetXMLNode(psFilterCap, "Comparison_Operators"))
     990               1 :             psFilterCap = CPLGetXMLNode(psFilterCap, "Comparison_Operators");
     991                 :         else
     992               0 :             psFilterCap = NULL;
     993              22 :         if (psFilterCap)
     994                 :         {
     995              22 :             if (CPLGetXMLNode(psFilterCap, "Simple_Comparisons") == NULL)
     996                 :             {
     997              21 :                 bHasMinOperators &= FindComparisonOperator(psFilterCap, "LessThan");
     998              21 :                 bHasMinOperators &= FindComparisonOperator(psFilterCap, "GreaterThan");
     999              21 :                 if (atoi(osVersion) >= 2)
    1000                 :                 {
    1001               6 :                     bHasMinOperators &= FindComparisonOperator(psFilterCap, "LessThanOrEqualTo");
    1002               6 :                     bHasMinOperators &= FindComparisonOperator(psFilterCap, "GreaterThanOrEqualTo");
    1003                 :                 }
    1004                 :                 else
    1005                 :                 {
    1006              15 :                     bHasMinOperators &= FindComparisonOperator(psFilterCap, "LessThanEqualTo");
    1007              15 :                     bHasMinOperators &= FindComparisonOperator(psFilterCap, "GreaterThanEqualTo");
    1008                 :                 }
    1009              21 :                 bHasMinOperators &= FindComparisonOperator(psFilterCap, "EqualTo");
    1010              21 :                 bHasMinOperators &= FindComparisonOperator(psFilterCap, "NotEqualTo");
    1011              21 :                 bHasMinOperators &= FindComparisonOperator(psFilterCap, "Like");
    1012                 :             }
    1013                 :             else
    1014                 :             {
    1015                 :                 bHasMinOperators &= CPLGetXMLNode(psFilterCap, "Simple_Comparisons") != NULL &&
    1016               1 :                                     CPLGetXMLNode(psFilterCap, "Like") != NULL;
    1017                 :             }
    1018                 :             bHasNullCheck = FindComparisonOperator(psFilterCap, "NullCheck") ||
    1019                 :                             FindComparisonOperator(psFilterCap, "Null") || /* WFS 2.0.0 */
    1020              22 :                             CPLGetXMLNode(psFilterCap, "NullCheck") != NULL;
    1021                 :         }
    1022                 :         else
    1023                 :         {
    1024               0 :             bHasMinOperators = FALSE;
    1025                 :         }
    1026                 :     }
    1027                 : 
    1028              22 :     CPLXMLNode* psChild = CPLGetXMLNode(psWFSCapabilities, "FeatureTypeList");
    1029              22 :     if (psChild == NULL)
    1030                 :     {
    1031                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1032               0 :                     "Cannot find <FeatureTypeList>");
    1033               0 :         if (!psFileXML) CPLDestroyXMLNode( psXML );
    1034               0 :         CPLDestroyXMLNode( psStrippedXML );
    1035               0 :         return FALSE;
    1036                 :     }
    1037                 : 
    1038                 :     CPLXMLNode* psChildIter;
    1039                 : 
    1040                 :     /* Check if there are layer names whose identical except their prefix */
    1041              22 :     std::set<CPLString> aosSetLayerNames;
    1042             396 :     for(psChildIter = psChild->psChild;
    1043                 :         psChildIter != NULL;
    1044                 :         psChildIter = psChildIter->psNext)
    1045                 :     {
    1046             381 :         if (psChildIter->eType == CXT_Element &&
    1047                 :             strcmp(psChildIter->pszValue, "FeatureType") == 0)
    1048                 :         {
    1049             372 :             const char* pszName = CPLGetXMLValue(psChildIter, "Name", NULL);
    1050             372 :             if (pszName != NULL)
    1051                 :             {
    1052             372 :                 const char* pszShortName = strchr(pszName, ':');
    1053             372 :                 if (pszShortName)
    1054             366 :                     pszName = pszShortName + 1;
    1055             372 :                 if (aosSetLayerNames.find(pszName) != aosSetLayerNames.end())
    1056                 :                 {
    1057               7 :                     bKeepLayerNamePrefix = TRUE;
    1058               7 :                     CPLDebug("WFS", "At least 2 layers have names that are only distinguishable by keeping the prefix");
    1059               7 :                     break;
    1060                 :                 }
    1061             365 :                 aosSetLayerNames.insert(pszName);
    1062                 :             }
    1063                 :         }
    1064                 :     }
    1065                 : 
    1066              22 :     char** papszTypenames = NULL;
    1067              22 :     if (osTypeName.size() != 0)
    1068               6 :         papszTypenames = CSLTokenizeStringComplex( osTypeName, ",", FALSE, FALSE );
    1069                 : 
    1070             533 :     for(psChildIter = psChild->psChild;
    1071                 :         psChildIter != NULL;
    1072                 :         psChildIter = psChildIter->psNext)
    1073                 :     {
    1074             511 :         if (psChildIter->eType == CXT_Element &&
    1075                 :             strcmp(psChildIter->pszValue, "FeatureType") == 0)
    1076                 :         {
    1077             502 :             const char* pszNS = NULL;
    1078             502 :             const char* pszNSVal = NULL;
    1079             502 :             CPLXMLNode* psFeatureTypeIter = psChildIter->psChild;
    1080            4430 :             while(psFeatureTypeIter != NULL)
    1081                 :             {
    1082            3426 :                 if (psFeatureTypeIter->eType == CXT_Attribute)
    1083                 :                 {
    1084             283 :                     pszNS = psFeatureTypeIter->pszValue;
    1085             283 :                     pszNSVal = psFeatureTypeIter->psChild->pszValue;
    1086                 :                 }
    1087            3426 :                 psFeatureTypeIter = psFeatureTypeIter->psNext;
    1088                 :             }
    1089                 : 
    1090             502 :             const char* pszName = CPLGetXMLValue(psChildIter, "Name", NULL);
    1091             502 :             const char* pszTitle = CPLGetXMLValue(psChildIter, "Title", NULL);
    1092             502 :             const char* pszAbstract = CPLGetXMLValue(psChildIter, "Abstract", NULL);
    1093             502 :             if (pszName != NULL &&
    1094                 :                 (papszTypenames == NULL ||
    1095                 :                  CSLFindString(papszTypenames, pszName) != -1))
    1096                 :             {
    1097                 :                 const char* pszDefaultSRS =
    1098             370 :                         CPLGetXMLValue(psChildIter, "DefaultSRS", NULL);
    1099             370 :                 if (pszDefaultSRS == NULL)
    1100              85 :                     pszDefaultSRS = CPLGetXMLValue(psChildIter, "SRS", NULL);
    1101             370 :                 if (pszDefaultSRS == NULL)
    1102              84 :                     pszDefaultSRS = CPLGetXMLValue(psChildIter, "DefaultCRS", NULL); /* WFS 2.0.0 */
    1103                 : 
    1104             370 :                 CPLXMLNode* psOutputFormats = CPLGetXMLNode(psChildIter, "OutputFormats");
    1105             370 :                 CPLString osOutputFormat;
    1106             370 :                 if (psOutputFormats)
    1107                 :                 {
    1108             292 :                     std::vector<CPLString> osFormats;
    1109             292 :                     CPLXMLNode* psOutputFormatIter = psOutputFormats->psChild;
    1110            1442 :                     while(psOutputFormatIter)
    1111                 :                     {
    1112             858 :                         if (psOutputFormatIter->eType == CXT_Element &&
    1113                 :                             EQUAL(psOutputFormatIter->pszValue, "Format") &&
    1114                 :                             psOutputFormatIter->psChild != NULL &&
    1115                 :                             psOutputFormatIter->psChild->eType == CXT_Text)
    1116                 :                         {
    1117             704 :                             osFormats.push_back(psOutputFormatIter->psChild->pszValue);
    1118                 :                         }
    1119             858 :                         psOutputFormatIter = psOutputFormatIter->psNext;
    1120                 :                     }
    1121                 : 
    1122             292 :                     if (strcmp(osVersion.c_str(), "1.1.0") == 0 && osFormats.size() > 0)
    1123                 :                     {
    1124             256 :                         int bFoundGML31 = FALSE;
    1125             570 :                         for(size_t i=0;i<osFormats.size();i++)
    1126                 :                         {
    1127             416 :                             if (strstr(osFormats[i].c_str(), "3.1") != NULL)
    1128                 :                             {
    1129             102 :                                 bFoundGML31 = TRUE;
    1130             102 :                                 break;
    1131                 :                             }
    1132                 :                         }
    1133                 : 
    1134                 :                         /* If we didn't find any mention to GML 3.1, then arbitrarily */
    1135                 :                         /* use the first output format */
    1136             256 :                         if (!bFoundGML31)
    1137             154 :                             osOutputFormat = osFormats[0].c_str();
    1138             292 :                     }
    1139                 :                 }
    1140                 : 
    1141             370 :                 OGRSpatialReference* poSRS = NULL;
    1142             370 :                 int bAxisOrderAlreadyInverted = FALSE;
    1143                 : 
    1144                 :                 /* If a SRSNAME parameter has been encoded in the URL, use it as the SRS */
    1145             370 :                 CPLString osSRSName = CPLURLGetValue(pszBaseURL, "SRSNAME");
    1146             370 :                 if (osSRSName.size() != 0)
    1147                 :                 {
    1148               0 :                     pszDefaultSRS = osSRSName.c_str();
    1149                 :                 }
    1150                 : 
    1151             370 :                 if (pszDefaultSRS)
    1152                 :                 {
    1153             370 :                     OGRSpatialReference oSRS;
    1154             370 :                     if (oSRS.SetFromUserInput(pszDefaultSRS) == OGRERR_NONE)
    1155                 :                     {
    1156             370 :                         poSRS = oSRS.Clone();
    1157             370 :                         if (bInvertAxisOrderIfLatLong &&
    1158                 :                             GML_IsSRSLatLongOrder(pszDefaultSRS))
    1159                 :                         {
    1160             214 :                             bAxisOrderAlreadyInverted = TRUE;
    1161                 : 
    1162                 :                             OGR_SRSNode *poGEOGCS =
    1163             214 :                                             poSRS->GetAttrNode( "GEOGCS" );
    1164             214 :                             if( poGEOGCS != NULL )
    1165                 :                             {
    1166             214 :                                 poGEOGCS->StripNodes( "AXIS" );
    1167                 :                             }
    1168                 :                         }
    1169             370 :                     }
    1170                 :                 }
    1171                 : 
    1172             370 :                 CPLXMLNode* psBBox = NULL;
    1173             370 :                 CPLXMLNode* psLatLongBBox = NULL;
    1174             370 :                 int bFoundBBox = FALSE;
    1175             370 :                 double dfMinX = 0, dfMinY = 0, dfMaxX = 0, dfMaxY = 0;
    1176             370 :                 if ((psBBox = CPLGetXMLNode(psChildIter, "WGS84BoundingBox")) != NULL)
    1177                 :                 {
    1178             369 :                     const char* pszLC = CPLGetXMLValue(psBBox, "LowerCorner", NULL);
    1179             369 :                     const char* pszUC = CPLGetXMLValue(psBBox, "UpperCorner", NULL);
    1180             369 :                     if (pszLC != NULL && pszUC != NULL)
    1181                 :                     {
    1182             369 :                         CPLString osConcat(pszLC);
    1183             369 :                         osConcat += " ";
    1184             369 :                         osConcat += pszUC;
    1185                 :                         char** papszTokens;
    1186                 :                         papszTokens = CSLTokenizeStringComplex(
    1187             369 :                                             osConcat, " ,", FALSE, FALSE );
    1188             369 :                         if (CSLCount(papszTokens) == 4)
    1189                 :                         {
    1190             369 :                             bFoundBBox = TRUE;
    1191             369 :                             dfMinX = CPLAtof(papszTokens[0]);
    1192             369 :                             dfMinY = CPLAtof(papszTokens[1]);
    1193             369 :                             dfMaxX = CPLAtof(papszTokens[2]);
    1194             369 :                             dfMaxY = CPLAtof(papszTokens[3]);
    1195                 :                         }
    1196             369 :                         CSLDestroy(papszTokens);
    1197                 :                     }
    1198                 :                 }
    1199               1 :                 else if ((psLatLongBBox = CPLGetXMLNode(psChildIter,
    1200                 :                                             "LatLongBoundingBox")) != NULL)
    1201                 :                 {
    1202                 :                     const char* pszMinX =
    1203               1 :                         CPLGetXMLValue(psLatLongBBox, "minx", NULL);
    1204                 :                     const char* pszMinY =
    1205               1 :                         CPLGetXMLValue(psLatLongBBox, "miny", NULL);
    1206                 :                     const char* pszMaxX =
    1207               1 :                         CPLGetXMLValue(psLatLongBBox, "maxx", NULL);
    1208                 :                     const char* pszMaxY =
    1209               1 :                         CPLGetXMLValue(psLatLongBBox, "maxy", NULL);
    1210               1 :                     if (pszMinX != NULL && pszMinY != NULL &&
    1211                 :                         pszMaxX != NULL && pszMaxY != NULL)
    1212                 :                     {
    1213               1 :                         bFoundBBox = TRUE;
    1214               1 :                         dfMinX = CPLAtof(pszMinX);
    1215               1 :                         dfMinY = CPLAtof(pszMinY);
    1216               1 :                         dfMaxX = CPLAtof(pszMaxX);
    1217               1 :                         dfMaxY = CPLAtof(pszMaxY);
    1218                 :                     }
    1219                 :                 }
    1220                 : 
    1221                 :                 char* pszCSVEscaped;
    1222                 : 
    1223             370 :                 pszCSVEscaped = CPLEscapeString(pszName, -1, CPLES_CSV);
    1224             370 :                 osLayerMetadataCSV += pszCSVEscaped;
    1225             370 :                 CPLFree(pszCSVEscaped);
    1226                 : 
    1227             370 :                 osLayerMetadataCSV += ",";
    1228             370 :                 if (pszTitle)
    1229                 :                 {
    1230             370 :                     pszCSVEscaped = CPLEscapeString(pszTitle, -1, CPLES_CSV);
    1231             370 :                     osLayerMetadataCSV += pszCSVEscaped;
    1232             370 :                     CPLFree(pszCSVEscaped);
    1233                 :                 }
    1234             370 :                 osLayerMetadataCSV += ",";
    1235             370 :                 if (pszAbstract)
    1236                 :                 {
    1237              82 :                     pszCSVEscaped = CPLEscapeString(pszAbstract, -1, CPLES_CSV);
    1238              82 :                     osLayerMetadataCSV += pszCSVEscaped;
    1239              82 :                     CPLFree(pszCSVEscaped);
    1240                 :                 }
    1241             370 :                 osLayerMetadataCSV += "\n";
    1242                 : 
    1243                 :                 OGRWFSLayer* poLayer = new OGRWFSLayer(
    1244                 :                             this, poSRS, bAxisOrderAlreadyInverted,
    1245             370 :                             pszBaseURL, pszName, pszNS, pszNSVal);
    1246             740 :                 if (osOutputFormat.size())
    1247             154 :                     poLayer->SetRequiredOutputFormat(osOutputFormat);
    1248                 : 
    1249             370 :                 if (poSRS)
    1250                 :                 {
    1251             370 :                     char* pszProj4 = NULL;
    1252             370 :                     if (poSRS->exportToProj4(&pszProj4) == OGRERR_NONE)
    1253                 :                     {
    1254                 :                         /* See http://trac.osgeo.org/gdal/ticket/4041 */
    1255                 :                         /* For now, we restrict to GEOSERVER as apparently the order is always longitude,latitude */
    1256                 :                         /* other servers might also qualify, so this should be relaxed */
    1257                 :                         /* Also accept when <wfs:DefaultCRS>urn:ogc:def:crs:OGC:1.3:CRS84</wfs:DefaultCRS> */
    1258             370 :                         if ((bIsGEOSERVER &&
    1259                 :                             (strcmp(pszProj4, "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ") == 0 ||
    1260                 :                              strcmp(pszProj4, "+proj=longlat +datum=WGS84 +no_defs ") == 0)) ||
    1261                 :                             strcmp(pszDefaultSRS, "urn:ogc:def:crs:OGC:1.3:CRS84") == 0)
    1262                 :                         {
    1263               0 :                             poLayer->SetExtents(dfMinX, dfMinY, dfMaxX, dfMaxY);
    1264                 :                         }
    1265                 : #if 0
    1266                 :                         else
    1267                 :                         {
    1268                 :                             OGRSpatialReference oWGS84;
    1269                 :                             oWGS84.SetWellKnownGeogCS("WGS84");
    1270                 :                             OGRCoordinateTransformation* poCT;
    1271                 :                             poCT = OGRCreateCoordinateTransformation(&oWGS84, poSRS);
    1272                 :                             if (poCT)
    1273                 :                             {
    1274                 :                                 double dfULX = dfMinX;
    1275                 :                                 double dfULY = dfMaxY;
    1276                 :                                 double dfURX = dfMaxX;
    1277                 :                                 double dfURY = dfMaxY;
    1278                 :                                 double dfLLX = dfMinX;
    1279                 :                                 double dfLLY = dfMinY;
    1280                 :                                 double dfLRX = dfMaxX;
    1281                 :                                 double dfLRY = dfMinY;
    1282                 :                                 if (poCT->Transform(1, &dfULX, &dfULY, NULL) &&
    1283                 :                                     poCT->Transform(1, &dfURX, &dfURY, NULL) &&
    1284                 :                                     poCT->Transform(1, &dfLLX, &dfLLY, NULL) &&
    1285                 :                                     poCT->Transform(1, &dfLRX, &dfLRY, NULL))
    1286                 :                                 {
    1287                 :                                     dfMinX = dfULX;
    1288                 :                                     dfMinX = MIN(dfMinX, dfURX);
    1289                 :                                     dfMinX = MIN(dfMinX, dfLLX);
    1290                 :                                     dfMinX = MIN(dfMinX, dfLRX);
    1291                 : 
    1292                 :                                     dfMinY = dfULY;
    1293                 :                                     dfMinY = MIN(dfMinY, dfURY);
    1294                 :                                     dfMinY = MIN(dfMinY, dfLLY);
    1295                 :                                     dfMinY = MIN(dfMinY, dfLRY);
    1296                 : 
    1297                 :                                     dfMaxX = dfULX;
    1298                 :                                     dfMaxX = MAX(dfMaxX, dfURX);
    1299                 :                                     dfMaxX = MAX(dfMaxX, dfLLX);
    1300                 :                                     dfMaxX = MAX(dfMaxX, dfLRX);
    1301                 : 
    1302                 :                                     dfMaxY = dfULY;
    1303                 :                                     dfMaxY = MAX(dfMaxY, dfURY);
    1304                 :                                     dfMaxY = MAX(dfMaxY, dfLLY);
    1305                 :                                     dfMaxY = MAX(dfMaxY, dfLRY);
    1306                 : 
    1307                 :                                     poLayer->SetExtents(dfMinX, dfMinY, dfMaxX, dfMaxY);
    1308                 :                                 }
    1309                 :                             }
    1310                 :                             delete poCT;
    1311                 :                         }
    1312                 : #endif
    1313                 :                     }
    1314             370 :                     CPLFree(pszProj4);
    1315                 :                 }
    1316                 : 
    1317                 :                 papoLayers = (OGRWFSLayer **)CPLRealloc(papoLayers,
    1318             370 :                                     sizeof(OGRWFSLayer*) * (nLayers + 1));
    1319             370 :                 papoLayers[nLayers ++] = poLayer;
    1320                 : 
    1321             370 :                 if (psFileXML != NULL)
    1322                 :                 {
    1323              49 :                     CPLXMLNode* psIter = psXML->psChild;
    1324             199 :                     while(psIter)
    1325                 :                     {
    1326             104 :                         if (psIter->eType == CXT_Element &&
    1327                 :                             EQUAL(psIter->pszValue, "OGRWFSLayer") &&
    1328                 :                             strcmp(CPLGetXMLValue(psIter, "name", ""), pszName) == 0)
    1329                 :                         {
    1330               3 :                             CPLXMLNode* psSchema = WFSFindNode( psIter->psChild, "schema" );
    1331               3 :                             if (psSchema)
    1332                 :                             {
    1333               3 :                                 OGRFeatureDefn* poSrcFDefn = poLayer->ParseSchema(psSchema);
    1334               3 :                                 if (poSrcFDefn)
    1335               3 :                                     poLayer->BuildLayerDefn(poSrcFDefn);
    1336                 :                             }
    1337               3 :                             break;
    1338                 :                         }
    1339             101 :                         psIter = psIter->psNext;
    1340                 :                     }
    1341             370 :                 }
    1342                 :             }
    1343                 :         }
    1344                 :     }
    1345                 : 
    1346              22 :     CSLDestroy(papszTypenames);
    1347                 : 
    1348              22 :     if (!psFileXML) CPLDestroyXMLNode( psXML );
    1349              22 :     CPLDestroyXMLNode( psStrippedXML );
    1350                 : 
    1351              22 :     return TRUE;
    1352                 : }
    1353                 : 
    1354                 : /************************************************************************/
    1355                 : /*                       LoadMultipleLayerDefn()                        */
    1356                 : /************************************************************************/
    1357                 : 
    1358                 : /* TinyOWS doesn't support POST, but MapServer, GeoServer and Deegree do */
    1359                 : #define USE_GET_FOR_DESCRIBE_FEATURE_TYPE 1
    1360                 : 
    1361              18 : void OGRWFSDataSource::LoadMultipleLayerDefn(const char* pszLayerName,
    1362                 :                                              char* pszNS, char* pszNSVal)
    1363                 : {
    1364                 :     /*if (!bIsGEOSERVER)
    1365                 :         return;*/
    1366                 : 
    1367              18 :     if (!bLoadMultipleLayerDefn)
    1368               1 :         return;
    1369                 : 
    1370              17 :     if (aoSetAlreadyTriedLayers.find(pszLayerName) != aoSetAlreadyTriedLayers.end())
    1371               0 :         return;
    1372                 : 
    1373              17 :     char* pszPrefix = CPLStrdup(pszLayerName);
    1374              17 :     char* pszColumn = strchr(pszPrefix, ':');
    1375              17 :     if (pszColumn)
    1376              16 :         *pszColumn = 0;
    1377                 :     else
    1378               1 :         *pszPrefix = 0;
    1379                 : 
    1380              17 :     OGRWFSLayer* poRefLayer = (OGRWFSLayer*)GetLayerByName(pszLayerName);
    1381              17 :     if (poRefLayer == NULL)
    1382               0 :         return;
    1383                 : 
    1384              17 :     const char* pszRequiredOutputFormat = poRefLayer->GetRequiredOutputFormat();
    1385                 : 
    1386                 : #if USE_GET_FOR_DESCRIBE_FEATURE_TYPE == 1
    1387              17 :     CPLString osLayerToFetch(pszLayerName);
    1388                 : #else
    1389                 :     CPLString osTypeNameToPost;
    1390                 :     osTypeNameToPost += "  <TypeName>";
    1391                 :     osTypeNameToPost += pszLayerName;
    1392                 :     osTypeNameToPost += "</TypeName>\n";
    1393                 : #endif
    1394                 : 
    1395              17 :     int nLayersToFetch = 1;
    1396              17 :     aoSetAlreadyTriedLayers.insert(pszLayerName);
    1397                 : 
    1398             203 :     for(int i=0;i<nLayers;i++)
    1399                 :     {
    1400             186 :         if (!papoLayers[i]->HasLayerDefn())
    1401                 :         {
    1402                 :             /* We must be careful to requests only layers with the same prefix/namespace */
    1403             186 :             const char* pszName = papoLayers[i]->GetName();
    1404             628 :             if (((pszPrefix[0] == 0 && strchr(pszName, ':') == NULL) ||
    1405             184 :                 (pszPrefix[0] != 0 && strncmp(pszName, pszPrefix, strlen(pszPrefix)) == 0 &&
    1406             128 :                  pszName[strlen(pszPrefix)] == ':')) &&
    1407             130 :                 ((pszRequiredOutputFormat == NULL && papoLayers[i]->GetRequiredOutputFormat() == NULL) ||
    1408               0 :                  (pszRequiredOutputFormat != NULL && papoLayers[i]->GetRequiredOutputFormat() != NULL &&
    1409               0 :                   strcmp(pszRequiredOutputFormat, papoLayers[i]->GetRequiredOutputFormat()) == 0)))
    1410                 :             {
    1411             130 :                 if (aoSetAlreadyTriedLayers.find(pszName) != aoSetAlreadyTriedLayers.end())
    1412              17 :                     continue;
    1413             113 :                 aoSetAlreadyTriedLayers.insert(pszName);
    1414                 : 
    1415                 : #if USE_GET_FOR_DESCRIBE_FEATURE_TYPE == 1
    1416             113 :                 if (nLayersToFetch > 0)
    1417             113 :                     osLayerToFetch += ",";
    1418             113 :                 osLayerToFetch += papoLayers[i]->GetName();
    1419                 : #else
    1420                 :                 osTypeNameToPost += "  <TypeName>";
    1421                 :                 osTypeNameToPost += pszName;
    1422                 :                 osTypeNameToPost += "</TypeName>\n";
    1423                 : #endif
    1424             113 :                 nLayersToFetch ++;
    1425                 : 
    1426                 :                 /* Avoid fetching to many layer definition at a time */
    1427             113 :                 if (nLayersToFetch >= 50)
    1428               0 :                     break;
    1429                 :             }
    1430                 :         }
    1431                 :     }
    1432                 : 
    1433              17 :     CPLFree(pszPrefix);
    1434              17 :     pszPrefix = NULL;
    1435                 : 
    1436                 : #if USE_GET_FOR_DESCRIBE_FEATURE_TYPE == 1
    1437              17 :     CPLString osURL(osBaseURL);
    1438              17 :     osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
    1439              17 :     osURL = CPLURLAddKVP(osURL, "VERSION", GetVersion());
    1440              17 :     osURL = CPLURLAddKVP(osURL, "REQUEST", "DescribeFeatureType");
    1441              17 :     osURL = CPLURLAddKVP(osURL, "TYPENAME", WFS_EscapeURL(osLayerToFetch));
    1442              17 :     osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", NULL);
    1443              17 :     osURL = CPLURLAddKVP(osURL, "MAXFEATURES", NULL);
    1444              17 :     osURL = CPLURLAddKVP(osURL, "FILTER", NULL);
    1445              17 :     osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", pszRequiredOutputFormat ? WFS_EscapeURL(pszRequiredOutputFormat).c_str() : NULL);
    1446                 : 
    1447              17 :     if (pszNS && GetNeedNAMESPACE())
    1448                 :     {
    1449                 :         /* Older Deegree version require NAMESPACE */
    1450                 :         /* This has been now corrected */
    1451               0 :         CPLString osValue("xmlns(");
    1452               0 :         osValue += pszNS;
    1453               0 :         osValue += "=";
    1454               0 :         osValue += pszNSVal;
    1455               0 :         osValue += ")";
    1456               0 :         osURL = CPLURLAddKVP(osURL, "NAMESPACE", WFS_EscapeURL(osValue));
    1457                 :     }
    1458                 : 
    1459              17 :     CPLHTTPResult* psResult = HTTPFetch( osURL, NULL);
    1460                 : #else
    1461                 :     CPLString osPost;
    1462                 :     osPost += "<?xml version=\"1.0\"?>\n";
    1463                 :     osPost += "<wfs:DescribeFeatureType xmlns:wfs=\"http://www.opengis.net/wfs\"\n";
    1464                 :     osPost += "                 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
    1465                 :     osPost += "                 service=\"WFS\" version=\""; osPost += GetVersion(); osPost += "\"\n";
    1466                 :     osPost += "                 xmlns:gml=\"http://www.opengis.net/gml\"\n";
    1467                 :     osPost += "                 xmlns:ogc=\"http://www.opengis.net/ogc\"\n";
    1468                 :     if (pszNS && pszNSVal)
    1469                 :     {
    1470                 :         osPost += "                 xmlns:";
    1471                 :         osPost += pszNS;
    1472                 :         osPost += "=\"";
    1473                 :         osPost += pszNSVal;
    1474                 :         osPost += "\"\n";
    1475                 :     }
    1476                 :     osPost += "                 xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/";
    1477                 :     osPost += GetVersion();
    1478                 :     osPost += "/wfs.xsd\"";
    1479                 :     const char* pszRequiredOutputFormat = poRefLayer->GetRequiredOutputFormat();
    1480                 :     if (pszRequiredOutputFormat)
    1481                 :     {
    1482                 :         osPost += "\n";
    1483                 :         osPost += "                 outputFormat=\"";
    1484                 :         osPost += pszRequiredOutputFormat;
    1485                 :         osPost += "\"";
    1486                 :     }
    1487                 :     osPost += ">\n";
    1488                 :     osPost += osTypeNameToPost;
    1489                 :     osPost += "</wfs:DescribeFeatureType>\n";
    1490                 : 
    1491                 :     //CPLDebug("WFS", "%s", osPost.c_str());
    1492                 : 
    1493                 :     char** papszOptions = NULL;
    1494                 :     papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    1495                 :     papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    1496                 :                                    "Content-Type: application/xml; charset=UTF-8");
    1497                 : 
    1498                 :     CPLHTTPResult* psResult = HTTPFetch(GetPostTransactionURL(), papszOptions);
    1499                 :     CSLDestroy(papszOptions);
    1500                 : #endif
    1501                 : 
    1502              17 :     if (psResult == NULL)
    1503                 :     {
    1504               0 :         bLoadMultipleLayerDefn = FALSE;
    1505                 :         return;
    1506                 :     }
    1507                 : 
    1508              17 :     if (strstr((const char*)psResult->pabyData, "<ServiceExceptionReport") != NULL)
    1509                 :     {
    1510               0 :         if (IsOldDeegree((const char*)psResult->pabyData))
    1511                 :         {
    1512                 :             /* just silently forgive */
    1513                 :         }
    1514                 :         else
    1515                 :         {
    1516                 :             CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    1517               0 :                     psResult->pabyData);
    1518                 :         }
    1519               0 :         CPLHTTPDestroyResult(psResult);
    1520               0 :         bLoadMultipleLayerDefn = FALSE;
    1521                 :         return;
    1522                 :     }
    1523                 : 
    1524              17 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    1525              17 :     if (psXML == NULL)
    1526                 :     {
    1527                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    1528               0 :                 psResult->pabyData);
    1529               0 :         CPLHTTPDestroyResult(psResult);
    1530               0 :         bLoadMultipleLayerDefn = FALSE;
    1531                 :         return;
    1532                 :     }
    1533              17 :     CPLHTTPDestroyResult(psResult);
    1534                 : 
    1535              17 :     CPLXMLNode* psSchema = WFSFindNode(psXML, "schema");
    1536              17 :     if (psSchema == NULL)
    1537                 :     {
    1538               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <Schema>");
    1539               0 :         CPLDestroyXMLNode( psXML );
    1540               0 :         bLoadMultipleLayerDefn = FALSE;
    1541                 :         return;
    1542                 :     }
    1543                 : 
    1544              17 :     CPLString osTmpFileName;
    1545                 : 
    1546              17 :     osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
    1547              17 :     CPLSerializeXMLTreeToFile(psSchema, osTmpFileName);
    1548                 : 
    1549              17 :     std::vector<GMLFeatureClass*> aosClasses;
    1550              17 :     GMLParseXSD( osTmpFileName, aosClasses );
    1551                 : 
    1552              17 :     int nLayersFound = 0;
    1553              17 :     if ((int)aosClasses.size() > 0)
    1554                 :     {
    1555              11 :         std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
    1556              11 :         std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
    1557              74 :         while (iter != eiter)
    1558                 :         {
    1559              52 :             GMLFeatureClass* poClass = *iter;
    1560              52 :             iter ++;
    1561                 : 
    1562                 :             OGRWFSLayer* poLayer;
    1563                 : 
    1564              52 :             if (bKeepLayerNamePrefix && pszNS != NULL && strchr(poClass->GetName(), ':') == NULL)
    1565                 :             {
    1566               0 :                 CPLString osWithPrefix(pszNS);
    1567               0 :                 osWithPrefix += ":";
    1568               0 :                 osWithPrefix += poClass->GetName();
    1569               0 :                 poLayer = (OGRWFSLayer* )GetLayerByName(osWithPrefix);
    1570                 :             }
    1571                 :             else
    1572              52 :                 poLayer = (OGRWFSLayer* )GetLayerByName(poClass->GetName());
    1573                 : 
    1574              52 :             if (poLayer)
    1575                 :             {
    1576              52 :                 if (!poLayer->HasLayerDefn())
    1577                 :                 {
    1578              52 :                     nLayersFound ++;
    1579                 : 
    1580              52 :                     CPLXMLNode* psSchemaForLayer = CPLCloneXMLTree(psSchema);
    1581              52 :                     CPLStripXMLNamespace( psSchemaForLayer, NULL, TRUE );
    1582              52 :                     CPLXMLNode* psIter = psSchemaForLayer->psChild;
    1583              52 :                     int bHasAlreadyImportedGML = FALSE;
    1584              52 :                     int bFoundComplexType = FALSE;
    1585              52 :                     int bFoundElement = FALSE;
    1586            1386 :                     while(psIter != NULL)
    1587                 :                     {
    1588            1282 :                         CPLXMLNode* psIterNext = psIter->psNext;
    1589            1324 :                         if (psIter->eType == CXT_Element &&
    1590                 :                             strcmp(psIter->pszValue,"complexType") == 0)
    1591                 :                         {
    1592              42 :                             const char* pszName = CPLGetXMLValue(psIter, "name", "");
    1593              42 :                             CPLString osExpectedName(poLayer->GetShortName());
    1594              42 :                             osExpectedName += "Type";
    1595              42 :                             CPLString osExpectedName2(poLayer->GetShortName());
    1596              42 :                             osExpectedName2 += "_Type";
    1597              42 :                             if (strcmp(pszName, osExpectedName) == 0 ||
    1598                 :                                 strcmp(pszName, osExpectedName2) == 0 ||
    1599                 :                                 strcmp(pszName, poLayer->GetShortName()) == 0)
    1600                 :                             {
    1601              16 :                                 bFoundComplexType = TRUE;
    1602                 :                             }
    1603                 :                             else
    1604                 :                             {
    1605              26 :                                 CPLRemoveXMLChild( psSchemaForLayer, psIter );
    1606              26 :                                 CPLDestroyXMLNode(psIter);
    1607              42 :                             }
    1608                 :                         }
    1609            1930 :                         else if (psIter->eType == CXT_Element &&
    1610                 :                                 strcmp(psIter->pszValue,"element") == 0)
    1611                 :                         {
    1612             690 :                             const char* pszName = CPLGetXMLValue(psIter, "name", "");
    1613             690 :                             CPLString osExpectedName(poLayer->GetShortName());
    1614             690 :                             osExpectedName += "Type";
    1615             690 :                             CPLString osExpectedName2(poLayer->GetShortName());
    1616             690 :                             osExpectedName2 += "_Type";
    1617                 : 
    1618             690 :                             const char* pszType = CPLGetXMLValue(psIter, "type", "");
    1619             690 :                             CPLString osExpectedType(poLayer->GetName());
    1620             690 :                             osExpectedType += "Type";
    1621             690 :                             CPLString osExpectedType2(poLayer->GetName());
    1622             690 :                             osExpectedType2 += "_Type";
    1623            1366 :                             if (strcmp(pszType, osExpectedType) == 0 ||
    1624                 :                                 strcmp(pszType, osExpectedType2) == 0 ||
    1625             676 :                                 strcmp(pszType, poLayer->GetName()) == 0 ||
    1626                 :                                 (strchr(pszType, ':') &&
    1627                 :                                  (strcmp(strchr(pszType, ':') + 1, osExpectedType) == 0 ||
    1628                 :                                   strcmp(strchr(pszType, ':') + 1, osExpectedType2) == 0)))
    1629                 :                             {
    1630              16 :                                 bFoundElement = TRUE;
    1631                 :                             }
    1632             674 :                             else if (*pszType == '\0' &&
    1633                 :                                      CPLGetXMLNode(psIter, "complexType") != NULL &&
    1634                 :                                      (strcmp(pszName, osExpectedName) == 0 ||
    1635                 :                                       strcmp(pszName, osExpectedName2) == 0 ||
    1636                 :                                       strcmp(pszName, poLayer->GetShortName()) == 0) )
    1637                 :                             {
    1638              36 :                                 bFoundElement = TRUE;
    1639              36 :                                 bFoundComplexType = TRUE;
    1640                 :                             }
    1641                 :                             else
    1642                 :                             {
    1643             638 :                                 CPLRemoveXMLChild( psSchemaForLayer, psIter );
    1644             638 :                                 CPLDestroyXMLNode(psIter);
    1645             690 :                             }
    1646                 :                         }
    1647             550 :                         else if (psIter->eType == CXT_Element &&
    1648                 :                                 strcmp(psIter->pszValue,"import") == 0 &&
    1649                 :                                 strcmp(CPLGetXMLValue(psIter, "namespace", ""),
    1650                 :                                         "http://www.opengis.net/gml") == 0)
    1651                 :                         {
    1652              10 :                             if (bHasAlreadyImportedGML)
    1653                 :                             {
    1654               0 :                                 CPLRemoveXMLChild( psSchemaForLayer, psIter );
    1655               0 :                                 CPLDestroyXMLNode(psIter);
    1656                 :                             }
    1657                 :                             else
    1658              10 :                                 bHasAlreadyImportedGML = TRUE;
    1659                 :                         }
    1660            1282 :                         psIter = psIterNext;
    1661                 :                     }
    1662                 : 
    1663              52 :                     if (bFoundComplexType && bFoundElement)
    1664                 :                     {
    1665              52 :                         OGRFeatureDefn* poSrcFDefn = poLayer->ParseSchema(psSchemaForLayer);
    1666              52 :                         if (poSrcFDefn)
    1667                 :                         {
    1668              52 :                             poLayer->BuildLayerDefn(poSrcFDefn);
    1669              52 :                             SaveLayerSchema(poLayer->GetName(), psSchemaForLayer);
    1670                 :                         }
    1671                 :                     }
    1672                 : 
    1673              52 :                     CPLDestroyXMLNode(psSchemaForLayer);
    1674                 :                 }
    1675                 :                 else
    1676                 :                 {
    1677                 :                     CPLDebug("WFS", "Found several time schema for layer %s in server response. Shouldn't happen",
    1678               0 :                              poClass->GetName());
    1679                 :                 }
    1680                 :             }
    1681              52 :             delete poClass;
    1682                 :         }
    1683                 :     }
    1684                 : 
    1685              17 :     if (nLayersFound != nLayersToFetch)
    1686                 :     {
    1687               6 :         CPLDebug("WFS", "Turn off loading of multiple layer definitions at a single time");
    1688               6 :         bLoadMultipleLayerDefn = FALSE;
    1689                 :     }
    1690                 : 
    1691              17 :     VSIUnlink(osTmpFileName);
    1692                 : 
    1693              17 :     CPLDestroyXMLNode( psXML );
    1694                 : }
    1695                 : 
    1696                 : /************************************************************************/
    1697                 : /*                         SaveLayerSchema()                            */
    1698                 : /************************************************************************/
    1699                 : 
    1700              59 : void OGRWFSDataSource::SaveLayerSchema(const char* pszLayerName, CPLXMLNode* psSchema)
    1701                 : {
    1702              59 :     if (psFileXML != NULL)
    1703                 :     {
    1704               4 :         bRewriteFile = TRUE;
    1705               4 :         CPLXMLNode* psLayerNode = CPLCreateXMLNode(NULL, CXT_Element, "OGRWFSLayer");
    1706               4 :         CPLSetXMLValue(psLayerNode, "#name", pszLayerName);
    1707               4 :         CPLAddXMLChild(psLayerNode, CPLCloneXMLTree(psSchema));
    1708               4 :         CPLAddXMLChild(psFileXML, psLayerNode);
    1709                 :     }
    1710              59 : }
    1711                 : 
    1712                 : /************************************************************************/
    1713                 : /*                           IsOldDeegree()                             */
    1714                 : /************************************************************************/
    1715                 : 
    1716               0 : int OGRWFSDataSource::IsOldDeegree(const char* pszErrorString)
    1717                 : {
    1718               0 :     if (!bNeedNAMESPACE &&
    1719                 :         strstr(pszErrorString, "Invalid \"TYPENAME\" parameter. No binding for prefix") != NULL)
    1720                 :     {
    1721               0 :         bNeedNAMESPACE = TRUE;
    1722               0 :         return TRUE;
    1723                 :     }
    1724               0 :     return FALSE;
    1725                 : }
    1726                 : 
    1727                 : /************************************************************************/
    1728                 : /*                         WFS_EscapeURL()                              */
    1729                 : /************************************************************************/
    1730                 : 
    1731             111 : CPLString WFS_EscapeURL(const char* pszURL)
    1732                 : {
    1733             111 :     CPLString osEscapedURL;
    1734                 : 
    1735                 :     /* Difference with CPLEscapeString(, CPLES_URL) : we do not escape */
    1736                 :     /* colon (:) or comma (,). Causes problems with servers such as http://www.mapinfo.com/miwfs? */
    1737                 : 
    1738           11103 :     for( int i = 0; pszURL[i] != '\0' ; i++ )
    1739                 :     {
    1740           10992 :         char ch = pszURL[i];
    1741           20698 :         if( (ch >= 'a' && ch <= 'z')
    1742                 :             || (ch >= 'A' && ch <= 'Z')
    1743                 :             || (ch >= '0' && ch <= '9')
    1744                 :             || ch == '_' || ch == '.'
    1745                 :             || ch == ':' || ch == ',' )
    1746                 :         {
    1747            9706 :             osEscapedURL += ch;
    1748                 :         }
    1749                 :         else
    1750                 :         {
    1751                 :             char szPercentEncoded[10];
    1752            1286 :             sprintf( szPercentEncoded, "%%%02X", ((unsigned char*)pszURL)[i] );
    1753            1286 :             osEscapedURL += szPercentEncoded;
    1754                 :         }
    1755                 :     }
    1756                 : 
    1757               0 :     return osEscapedURL;
    1758                 : }
    1759                 : 
    1760                 : /************************************************************************/
    1761                 : /*                            HTTPFetch()                               */
    1762                 : /************************************************************************/
    1763                 : 
    1764              65 : CPLHTTPResult* OGRWFSDataSource::HTTPFetch( const char* pszURL, char** papszOptions )
    1765                 : {
    1766              65 :     char** papszNewOptions = CSLDuplicate(papszOptions);
    1767              65 :     if (bUseHttp10)
    1768               0 :         papszNewOptions = CSLAddNameValue(papszNewOptions, "HTTP_VERSION", "1.0");
    1769              65 :     if (papszHttpOptions)
    1770               0 :         papszNewOptions = CSLMerge(papszNewOptions, papszHttpOptions);
    1771              65 :     CPLHTTPResult* psResult = CPLHTTPFetch( pszURL, papszNewOptions );
    1772              65 :     CSLDestroy(papszNewOptions);
    1773                 :     
    1774              65 :     if (psResult == NULL)
    1775                 :     {
    1776               0 :         return NULL;
    1777                 :     }
    1778              65 :     if (psResult->nStatus != 0 || psResult->pszErrBuf != NULL)
    1779                 :     {
    1780                 :         /* A few buggy servers return chunked data with errouneous remaining bytes value */
    1781                 :         /* curl doesn't like this. Retry with HTTP 1.0 protocol instead that doesn't support */
    1782                 :         /* chunked data */
    1783               0 :         if (psResult->pszErrBuf &&
    1784                 :             strstr(psResult->pszErrBuf, "transfer closed with outstanding read data remaining") &&
    1785                 :             !bUseHttp10)
    1786                 :         {
    1787               0 :             CPLDebug("WFS", "Probably buggy remote server. Retrying with HTTP 1.0 protocol");
    1788               0 :             bUseHttp10 = TRUE;
    1789               0 :             return HTTPFetch(pszURL, papszOptions);
    1790                 :         }
    1791                 : 
    1792                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s (%d)",
    1793               0 :                  (psResult->pszErrBuf) ? psResult->pszErrBuf : "unknown", psResult->nStatus);
    1794               0 :         CPLHTTPDestroyResult(psResult);
    1795               0 :         return NULL;
    1796                 :     }
    1797              65 :     if (psResult->pabyData == NULL)
    1798                 :     {
    1799               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server");
    1800               0 :         CPLHTTPDestroyResult(psResult);
    1801               0 :         return NULL;
    1802                 :     }
    1803              65 :     return psResult;
    1804                 : }
    1805                 : 
    1806                 : /************************************************************************/
    1807                 : /*                             ExecuteSQL()                             */
    1808                 : /************************************************************************/
    1809                 : 
    1810               9 : OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
    1811                 :                                         OGRGeometry *poSpatialFilter,
    1812                 :                                         const char *pszDialect )
    1813                 : 
    1814                 : {
    1815                 : /* -------------------------------------------------------------------- */
    1816                 : /*      Use generic implementation for OGRSQL dialect.                  */
    1817                 : /* -------------------------------------------------------------------- */
    1818               9 :     if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
    1819                 :     {
    1820                 :         OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
    1821                 :                                                           poSpatialFilter,
    1822               0 :                                                           pszDialect );
    1823               0 :         oMap[poResLayer] = NULL;
    1824               0 :         return poResLayer;
    1825                 :     }
    1826                 : 
    1827                 : /* -------------------------------------------------------------------- */
    1828                 : /*      Deal with "SELECT _LAST_INSERTED_FIDS_ FROM layername" statement */
    1829                 : /* -------------------------------------------------------------------- */
    1830               9 :     if( EQUALN(pszSQLCommand, "SELECT _LAST_INSERTED_FIDS_ FROM ", 33) )
    1831                 :     {
    1832               1 :         const char* pszIter = pszSQLCommand + 33;
    1833              14 :         while(*pszIter && *pszIter != ' ')
    1834              12 :             pszIter ++;
    1835                 : 
    1836               1 :         CPLString osName = pszSQLCommand + 33;
    1837               1 :         osName.resize(pszIter - (pszSQLCommand + 33));
    1838               1 :         OGRWFSLayer* poLayer = (OGRWFSLayer*)GetLayerByName(osName);
    1839               1 :         if (poLayer == NULL)
    1840                 :         {
    1841                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1842               0 :                      "Unknown layer : %s", osName.c_str());
    1843               0 :             return NULL;
    1844                 :         }
    1845                 : 
    1846               1 :         OGRSFDriver* poMEMDrv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
    1847               1 :         if (poMEMDrv == NULL)
    1848                 :         {
    1849               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot load 'Memory' driver");
    1850               0 :             return NULL;
    1851                 :         }
    1852                 : 
    1853               1 :         OGRDataSource* poMEMDS = poMEMDrv->CreateDataSource("dummy_name", NULL);
    1854               1 :         OGRLayer* poMEMLayer = poMEMDS->CreateLayer("FID_LIST", NULL, wkbNone, NULL);
    1855               1 :         OGRFieldDefn oFDefn("gml_id", OFTString);
    1856               1 :         poMEMLayer->CreateField(&oFDefn);
    1857                 : 
    1858               1 :         const std::vector<CPLString>& aosFIDList = poLayer->GetLastInsertedFIDList();
    1859               1 :         std::vector<CPLString>::const_iterator iter = aosFIDList.begin();
    1860               1 :         std::vector<CPLString>::const_iterator eiter = aosFIDList.end();
    1861               4 :         while (iter != eiter)
    1862                 :         {
    1863               2 :             const CPLString& osFID = *iter;
    1864               2 :             OGRFeature* poFeature = new OGRFeature(poMEMLayer->GetLayerDefn());
    1865               4 :             poFeature->SetField(0, osFID);
    1866               2 :             poMEMLayer->CreateFeature(poFeature);
    1867               2 :             delete poFeature;
    1868               2 :             iter ++;
    1869                 :         }
    1870                 : 
    1871               1 :         OGRLayer* poResLayer = new OGRWFSWrappedResultLayer(poMEMDS, poMEMLayer);
    1872               2 :         oMap[poResLayer] = NULL;
    1873               1 :         return poResLayer;
    1874                 :     }
    1875                 : 
    1876                 : /* -------------------------------------------------------------------- */
    1877                 : /*      Deal with "DELETE FROM layer_name WHERE expression" statement   */
    1878                 : /* -------------------------------------------------------------------- */
    1879               8 :     if( EQUALN(pszSQLCommand, "DELETE FROM ", 12) )
    1880                 :     {
    1881               1 :         const char* pszIter = pszSQLCommand + 12;
    1882              14 :         while(*pszIter && *pszIter != ' ')
    1883              12 :             pszIter ++;
    1884               1 :         if (*pszIter == 0)
    1885                 :         {
    1886               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid statement");
    1887               0 :             return NULL;
    1888                 :         }
    1889                 : 
    1890               1 :         CPLString osName = pszSQLCommand + 12;
    1891               1 :         osName.resize(pszIter - (pszSQLCommand + 12));
    1892               1 :         OGRWFSLayer* poLayer = (OGRWFSLayer*)GetLayerByName(osName);
    1893               1 :         if (poLayer == NULL)
    1894                 :         {
    1895                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1896               0 :                      "Unknown layer : %s", osName.c_str());
    1897               0 :             return NULL;
    1898                 :         }
    1899                 : 
    1900               3 :         while(*pszIter && *pszIter == ' ')
    1901               1 :             pszIter ++;
    1902               1 :         if (!EQUALN(pszIter, "WHERE ", 5))
    1903                 :         {
    1904               0 :             CPLError(CE_Failure, CPLE_AppDefined, "WHERE clause missing");
    1905               0 :             return NULL;
    1906                 :         }
    1907               1 :         pszIter += 5;
    1908                 : 
    1909               1 :         const char* pszQuery = pszIter;
    1910                 : 
    1911                 :         /* Check with the generic SQL engine that this is a valid WHERE clause */
    1912               1 :         OGRFeatureQuery oQuery;
    1913               1 :         OGRErr eErr = oQuery.Compile( poLayer->GetLayerDefn(), pszQuery );
    1914               1 :         if( eErr != OGRERR_NONE )
    1915                 :         {
    1916               0 :             return NULL;
    1917                 :         }
    1918                 : 
    1919                 :         /* Now turn this into OGC Filter language if possible */
    1920               1 :         int bNeedsNullCheck = FALSE;
    1921               1 :         int nVersion = (strcmp(GetVersion(),"1.0.0") == 0) ? 100 : 110;
    1922                 :         CPLString osOGCFilter = WFS_TurnSQLFilterToOGCFilter(pszQuery,
    1923               1 :                                                              poLayer->GetLayerDefn(),
    1924                 :                                                              nVersion,
    1925                 :                                                              bPropertyIsNotEqualToSupported,
    1926                 :                                                              bUseFeatureId,
    1927                 :                                                              bGmlObjectIdNeedsGMLPrefix,
    1928               2 :                                                              &bNeedsNullCheck);
    1929               1 :         if (bNeedsNullCheck && !HasNullCheck())
    1930               0 :             osOGCFilter = "";
    1931                 : 
    1932               1 :         if (osOGCFilter.size() == 0)
    1933                 :         {
    1934               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot convert WHERE clause into a OGC filter");
    1935               0 :             return NULL;
    1936                 :         }
    1937                 : 
    1938               1 :         poLayer->DeleteFromFilter(osOGCFilter);
    1939                 : 
    1940               1 :         return NULL;
    1941                 :     }
    1942                 : 
    1943                 : /* -------------------------------------------------------------------- */
    1944                 : /*      Deal with "SELECT xxxx ORDER BY" statement                      */
    1945                 : /* -------------------------------------------------------------------- */
    1946               7 :     if (EQUALN(pszSQLCommand, "SELECT", 6))
    1947                 :     {
    1948               5 :         swq_select* psSelectInfo = new swq_select();
    1949               5 :         if( psSelectInfo->preparse( pszSQLCommand ) != CPLE_None )
    1950                 :         {
    1951               0 :             delete psSelectInfo;
    1952               0 :             return NULL;
    1953                 :         }
    1954                 :         int iLayer;
    1955              15 :         if( strcmp(GetVersion(),"1.0.0") != 0 &&
    1956                 :             psSelectInfo->table_count == 1 &&
    1957               5 :             psSelectInfo->table_defs[0].data_source == NULL &&
    1958               5 :             (iLayer = GetLayerIndex( psSelectInfo->table_defs[0].table_name )) >= 0 &&
    1959                 :             psSelectInfo->join_count == 0 &&
    1960                 :             psSelectInfo->order_specs == 1 )
    1961                 :         {
    1962               1 :             OGRWFSLayer* poSrcLayer = papoLayers[iLayer];
    1963               1 :             int nFieldIndex = poSrcLayer->GetLayerDefn()->GetFieldIndex(
    1964               2 :                                         psSelectInfo->order_defs[0].field_name);
    1965               1 :             if (!poSrcLayer->HasGotApproximateLayerDefn() && nFieldIndex >= 0)
    1966                 :             {
    1967               1 :                 OGRWFSLayer* poDupLayer = poSrcLayer->Clone(); 
    1968                 : 
    1969                 :                 /* Make sure to have the right case */
    1970               1 :                 const char* pszFieldName = poDupLayer->GetLayerDefn()->
    1971               1 :                     GetFieldDefn(nFieldIndex)->GetNameRef();
    1972                 : 
    1973                 :                 poDupLayer->SetOrderBy(pszFieldName,
    1974               1 :                                        psSelectInfo->order_defs[0].ascending_flag);
    1975               1 :                 delete psSelectInfo;
    1976               1 :                 psSelectInfo = NULL;
    1977                 : 
    1978                 :                 /* Just set poDupLayer in the papoLayers for the time of the */
    1979                 :                 /* base ExecuteSQL(), so that the OGRGenSQLResultsLayer references */
    1980                 :                 /* that temporary layer */
    1981               1 :                 papoLayers[iLayer] = poDupLayer;
    1982                 :                 OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
    1983                 :                                                                   poSpatialFilter,
    1984               1 :                                                                   pszDialect );
    1985               1 :                 papoLayers[iLayer] = poSrcLayer;
    1986                 : 
    1987               1 :                 if (poResLayer != NULL)
    1988               1 :                     oMap[poResLayer] = poDupLayer;
    1989                 :                 else
    1990               0 :                     delete poDupLayer;
    1991               1 :                 return poResLayer;
    1992                 :             }
    1993                 :         }
    1994                 : 
    1995               4 :         delete psSelectInfo;
    1996                 :     }
    1997                 : 
    1998                 :     OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
    1999                 :                                                       poSpatialFilter,
    2000               6 :                                                       pszDialect );
    2001               6 :     oMap[poResLayer] = NULL;
    2002               6 :     return poResLayer;
    2003                 : }
    2004                 : 
    2005                 : /************************************************************************/
    2006                 : /*                          ReleaseResultSet()                          */
    2007                 : /************************************************************************/
    2008                 : 
    2009               7 : void OGRWFSDataSource::ReleaseResultSet( OGRLayer * poResultsSet )
    2010                 : {
    2011               7 :     if (poResultsSet == NULL)
    2012               1 :         return;
    2013                 : 
    2014               6 :     std::map<OGRLayer*, OGRLayer*>::iterator oIter = oMap.find(poResultsSet);
    2015               6 :     if (oIter != oMap.end())
    2016                 :     {
    2017                 :         /* Destroy first the result layer, because it still references */
    2018                 :         /* the poDupLayer (oIter->second) */
    2019               6 :         delete poResultsSet;
    2020                 : 
    2021               6 :         delete oIter->second;
    2022               6 :         oMap.erase(oIter);
    2023                 :     }
    2024                 :     else
    2025                 :     {
    2026               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Trying to destroy an invalid result set !");
    2027                 :     }
    2028                 : }

Generated by: LCOV version 1.7