LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfsdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 940 654 69.6 %
Date: 2012-04-28 Functions: 36 21 58.3 %

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

Generated by: LCOV version 1.7