LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfsdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 945 719 76.1 %
Date: 2013-03-30 Functions: 36 22 61.1 %

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

Generated by: LCOV version 1.7