LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfsdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 904 716 79.2 %
Date: 2011-12-18 Functions: 36 25 69.4 %

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

Generated by: LCOV version 1.7