LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfslayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1254 846 67.5 %
Date: 2012-12-26 Functions: 39 34 87.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrwfslayer.cpp 24791 2012-08-15 20:48:55Z rouault $
       3                 :  *
       4                 :  * Project:  WFS Translator
       5                 :  * Purpose:  Implements OGRWFSLayer 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 "parsexsd.h"
      36                 : 
      37                 : CPL_CVSID("$Id: ogrwfslayer.cpp 24791 2012-08-15 20:48:55Z rouault $");
      38                 : 
      39                 : 
      40                 : /************************************************************************/
      41                 : /*                      OGRWFSRecursiveUnlink()                         */
      42                 : /************************************************************************/
      43                 : 
      44             371 : static void OGRWFSRecursiveUnlink( const char *pszName )
      45                 : 
      46                 : {
      47                 :     char **papszFileList;
      48                 :     int i;
      49                 : 
      50             371 :     papszFileList = CPLReadDir( pszName );
      51                 : 
      52             439 :     for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
      53                 :     {
      54                 :         VSIStatBufL  sStatBuf;
      55                 : 
      56              68 :         if( EQUAL(papszFileList[i],".") || EQUAL(papszFileList[i],"..") )
      57               0 :             continue;
      58                 : 
      59                 :         CPLString osFullFilename =
      60              68 :                  CPLFormFilename( pszName, papszFileList[i], NULL );
      61                 : 
      62              68 :         VSIStatL( osFullFilename, &sStatBuf );
      63                 : 
      64              68 :         if( VSI_ISREG( sStatBuf.st_mode ) )
      65                 :         {
      66              68 :             VSIUnlink( osFullFilename );
      67                 :         }
      68               0 :         else if( VSI_ISDIR( sStatBuf.st_mode ) )
      69                 :         {
      70               0 :             OGRWFSRecursiveUnlink( osFullFilename );
      71                 :         }
      72                 :     }
      73                 : 
      74             371 :     CSLDestroy( papszFileList );
      75                 : 
      76             371 :     VSIRmdir( pszName );
      77             371 : }
      78                 : 
      79                 : /************************************************************************/
      80                 : /*                            OGRWFSLayer()                             */
      81                 : /************************************************************************/
      82                 : 
      83             371 : OGRWFSLayer::OGRWFSLayer( OGRWFSDataSource* poDS,
      84                 :                           OGRSpatialReference* poSRS,
      85                 :                           int bAxisOrderAlreadyInverted,
      86                 :                           const char* pszBaseURL,
      87                 :                           const char* pszName,
      88                 :                           const char* pszNS,
      89             371 :                           const char* pszNSVal )
      90                 : 
      91                 : {
      92             371 :     this->poDS = poDS;
      93             371 :     this->poSRS = poSRS;
      94             371 :     this->bAxisOrderAlreadyInverted = bAxisOrderAlreadyInverted;
      95             371 :     this->pszBaseURL = CPLStrdup(pszBaseURL);
      96             371 :     this->pszName = CPLStrdup(pszName);
      97             371 :     this->pszNS = pszNS ? CPLStrdup(pszNS) : NULL;
      98             371 :     this->pszNSVal = pszNSVal ? CPLStrdup(pszNSVal) : NULL;
      99                 : 
     100             371 :     poFeatureDefn = NULL;
     101             371 :     poGMLFeatureClass = NULL;
     102             371 :     bGotApproximateLayerDefn = FALSE;
     103                 : 
     104             371 :     bStreamingDS = FALSE;
     105             371 :     poBaseDS = NULL;
     106             371 :     poBaseLayer = NULL;
     107             371 :     bReloadNeeded = FALSE;
     108             371 :     bHasFetched = FALSE;
     109             371 :     eGeomType = wkbUnknown;
     110             371 :     nFeatures = -1;
     111                 : 
     112             371 :     dfMinX = dfMinY = dfMaxX = dfMaxY = 0;
     113             371 :     bHasExtents = FALSE;
     114             371 :     poFetchedFilterGeom = NULL;
     115                 : 
     116             371 :     nExpectedInserts = 0;
     117             371 :     bInTransaction = FALSE;
     118             371 :     bUseFeatureIdAtLayerLevel = FALSE;
     119                 : 
     120             371 :     bPagingActive = FALSE;
     121             371 :     nPagingStartIndex = 0;
     122             371 :     nFeatureRead = 0;
     123             371 :     nFeatureCountRequested = 0;
     124                 : 
     125             371 :     pszRequiredOutputFormat = NULL;
     126                 : 
     127             371 :     bAscFlag = TRUE;
     128             371 : }
     129                 : 
     130                 : /************************************************************************/
     131                 : /*                             Clone()                                  */
     132                 : /************************************************************************/
     133                 : 
     134               1 : OGRWFSLayer* OGRWFSLayer::Clone()
     135                 : {
     136                 :     OGRWFSLayer* poDupLayer = new OGRWFSLayer(poDS, poSRS, bAxisOrderAlreadyInverted,
     137               1 :                                               pszBaseURL, pszName, pszNS, pszNSVal);
     138               1 :     if (poSRS)
     139               1 :         poSRS->Reference();
     140               1 :     poDupLayer->poFeatureDefn = GetLayerDefn()->Clone();
     141               1 :     poDupLayer->poFeatureDefn->Reference();
     142               1 :     poDupLayer->bGotApproximateLayerDefn = bGotApproximateLayerDefn;
     143               1 :     poDupLayer->eGeomType = poDupLayer->poFeatureDefn->GetGeomType();
     144               1 :     poDupLayer->pszRequiredOutputFormat = pszRequiredOutputFormat ? CPLStrdup(pszRequiredOutputFormat) : NULL;
     145               1 :     poDupLayer->bAscFlag = bAscFlag;
     146                 : 
     147                 :     /* Copy existing schema file if already found */
     148               1 :     CPLString osSrcFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
     149               1 :     CPLString osTargetFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", poDupLayer);
     150               1 :     CPLCopyFile(osTargetFileName, osSrcFileName);
     151                 : 
     152               1 :     return poDupLayer;
     153                 : }
     154                 : 
     155                 : /************************************************************************/
     156                 : /*                            ~OGRWFSLayer()                            */
     157                 : /************************************************************************/
     158                 : 
     159             371 : OGRWFSLayer::~OGRWFSLayer()
     160                 : 
     161                 : {
     162             371 :     if (bInTransaction)
     163               0 :         CommitTransaction();
     164                 : 
     165             371 :     if( poSRS != NULL )
     166             371 :         poSRS->Release();
     167                 : 
     168             371 :     if (poFeatureDefn != NULL)
     169              63 :         poFeatureDefn->Release();
     170             371 :     delete poGMLFeatureClass;
     171                 : 
     172             371 :     CPLFree(pszBaseURL);
     173             371 :     CPLFree(pszName);
     174             371 :     CPLFree(pszNS);
     175             371 :     CPLFree(pszNSVal);
     176                 : 
     177             371 :     OGRDataSource::DestroyDataSource(poBaseDS);
     178                 : 
     179             371 :     delete poFetchedFilterGeom;
     180                 : 
     181             371 :     CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
     182             371 :     OGRWFSRecursiveUnlink(osTmpDirName);
     183                 : 
     184             371 :     CPLFree(pszRequiredOutputFormat);
     185             371 : }
     186                 : 
     187                 : /************************************************************************/
     188                 : /*                    GetDescribeFeatureTypeURL()                       */
     189                 : /************************************************************************/
     190                 : 
     191              12 : CPLString OGRWFSLayer::GetDescribeFeatureTypeURL(int bWithNS)
     192                 : {
     193              12 :     CPLString osURL(pszBaseURL);
     194              12 :     osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
     195              12 :     osURL = CPLURLAddKVP(osURL, "VERSION", poDS->GetVersion());
     196              12 :     osURL = CPLURLAddKVP(osURL, "REQUEST", "DescribeFeatureType");
     197              12 :     osURL = CPLURLAddKVP(osURL, "TYPENAME", WFS_EscapeURL(pszName));
     198              12 :     osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", NULL);
     199              12 :     osURL = CPLURLAddKVP(osURL, "MAXFEATURES", NULL);
     200              12 :     osURL = CPLURLAddKVP(osURL, "COUNT", NULL);
     201              12 :     osURL = CPLURLAddKVP(osURL, "FILTER", NULL);
     202              12 :     osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", pszRequiredOutputFormat ? WFS_EscapeURL(pszRequiredOutputFormat).c_str() : NULL);
     203                 : 
     204              12 :     if (pszNS && poDS->GetNeedNAMESPACE())
     205                 :     {
     206                 :         /* Older Deegree version require NAMESPACE (e.g. http://www.nokis.org/deegree2/ogcwebservice) */
     207                 :         /* This has been now corrected */
     208               0 :         CPLString osValue("xmlns(");
     209               0 :         osValue += pszNS;
     210               0 :         osValue += "=";
     211               0 :         osValue += pszNSVal;
     212               0 :         osValue += ")";
     213               0 :         osURL = CPLURLAddKVP(osURL, "NAMESPACE", WFS_EscapeURL(osValue));
     214                 :     }
     215                 : 
     216               0 :     return osURL;
     217                 : }
     218                 : 
     219                 : /************************************************************************/
     220                 : /*                      DescribeFeatureType()                           */
     221                 : /************************************************************************/
     222                 : 
     223               7 : OGRFeatureDefn* OGRWFSLayer::DescribeFeatureType()
     224                 : {
     225               7 :     CPLString osURL = GetDescribeFeatureTypeURL(TRUE);
     226                 : 
     227               7 :     CPLDebug("WFS", "%s", osURL.c_str());
     228                 : 
     229               7 :     CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
     230               7 :     if (psResult == NULL)
     231                 :     {
     232               0 :         return NULL;
     233                 :     }
     234                 : 
     235               7 :     if (strstr((const char*)psResult->pabyData, "<ServiceExceptionReport") != NULL)
     236                 :     {
     237               0 :         if (poDS->IsOldDeegree((const char*)psResult->pabyData))
     238                 :         {
     239               0 :             CPLHTTPDestroyResult(psResult);
     240               0 :             return DescribeFeatureType();
     241                 :         }
     242                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
     243               0 :                  psResult->pabyData);
     244               0 :         CPLHTTPDestroyResult(psResult);
     245               0 :         return NULL;
     246                 :     }
     247                 : 
     248               7 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
     249               7 :     if (psXML == NULL)
     250                 :     {
     251                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
     252               0 :                 psResult->pabyData);
     253               0 :         CPLHTTPDestroyResult(psResult);
     254               0 :         return NULL;
     255                 :     }
     256               7 :     CPLHTTPDestroyResult(psResult);
     257                 : 
     258               7 :     CPLXMLNode* psSchema = WFSFindNode(psXML, "schema");
     259               7 :     if (psSchema == NULL)
     260                 :     {
     261               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <Schema>");
     262               0 :         CPLDestroyXMLNode( psXML );
     263                 : 
     264               0 :         return NULL;
     265                 :     }
     266                 : 
     267               7 :     OGRFeatureDefn* poFDefn = ParseSchema(psSchema);
     268               7 :     if (poFDefn)
     269               7 :         poDS->SaveLayerSchema(pszName, psSchema);
     270                 : 
     271               7 :     CPLDestroyXMLNode( psXML );
     272               7 :     return poFDefn;
     273                 : }
     274                 : 
     275                 : /************************************************************************/
     276                 : /*                            ParseSchema()                             */
     277                 : /************************************************************************/
     278                 : 
     279              62 : OGRFeatureDefn* OGRWFSLayer::ParseSchema(CPLXMLNode* psSchema)
     280                 : {
     281              62 :     osTargetNamespace = CPLGetXMLValue(psSchema, "targetNamespace", "");
     282                 : 
     283              62 :     CPLString osTmpFileName;
     284                 : 
     285             124 :     osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
     286              62 :     CPLSerializeXMLTreeToFile(psSchema, osTmpFileName);
     287                 : 
     288              62 :     std::vector<GMLFeatureClass*> aosClasses;
     289              62 :     int bHaveSchema = GMLParseXSD( osTmpFileName, aosClasses );
     290                 : 
     291              62 :     if (bHaveSchema && aosClasses.size() == 1)
     292                 :     {
     293                 :         //CPLDebug("WFS", "Creating %s for %s", osTmpFileName.c_str(), GetName());
     294              62 :         return BuildLayerDefnFromFeatureClass(aosClasses[0]);
     295                 :     }
     296               0 :     else if (bHaveSchema)
     297                 :     {
     298               0 :         std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
     299               0 :         std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
     300               0 :         while (iter != eiter)
     301                 :         {
     302               0 :             GMLFeatureClass* poClass = *iter;
     303               0 :             iter ++;
     304               0 :             delete poClass;
     305                 :         }
     306                 :     }
     307                 : 
     308               0 :     VSIUnlink(osTmpFileName);
     309                 : 
     310               0 :     return NULL;
     311                 : }
     312                 : /************************************************************************/
     313                 : /*                   BuildLayerDefnFromFeatureClass()                   */
     314                 : /************************************************************************/
     315                 : 
     316              62 : OGRFeatureDefn* OGRWFSLayer::BuildLayerDefnFromFeatureClass(GMLFeatureClass* poClass)
     317                 : {
     318              62 :     this->poGMLFeatureClass = poClass;
     319                 : 
     320              62 :     OGRFeatureDefn* poFDefn = new OGRFeatureDefn( pszName );
     321              62 :     poFDefn->SetGeomType( (OGRwkbGeometryType)poGMLFeatureClass->GetGeometryType() );
     322                 : 
     323                 : /* -------------------------------------------------------------------- */
     324                 : /*      Added attributes (properties).                                  */
     325                 : /* -------------------------------------------------------------------- */
     326              62 :     OGRFieldDefn oField( "gml_id", OFTString );
     327              62 :     poFDefn->AddFieldDefn( &oField );
     328                 : 
     329             344 :     for( int iField = 0; iField < poGMLFeatureClass->GetPropertyCount(); iField++ )
     330                 :     {
     331             282 :         GMLPropertyDefn *poProperty = poGMLFeatureClass->GetProperty( iField );
     332                 :         OGRFieldType eFType;
     333                 : 
     334             282 :         if( poProperty->GetType() == GMLPT_Untyped )
     335               0 :             eFType = OFTString;
     336             282 :         else if( poProperty->GetType() == GMLPT_String )
     337             110 :             eFType = OFTString;
     338             172 :         else if( poProperty->GetType() == GMLPT_Integer )
     339              30 :             eFType = OFTInteger;
     340             142 :         else if( poProperty->GetType() == GMLPT_Real )
     341             142 :             eFType = OFTReal;
     342               0 :         else if( poProperty->GetType() == GMLPT_StringList )
     343               0 :             eFType = OFTStringList;
     344               0 :         else if( poProperty->GetType() == GMLPT_IntegerList )
     345               0 :             eFType = OFTIntegerList;
     346               0 :         else if( poProperty->GetType() == GMLPT_RealList )
     347               0 :             eFType = OFTRealList;
     348                 :         else
     349               0 :             eFType = OFTString;
     350                 : 
     351             282 :         OGRFieldDefn oField( poProperty->GetName(), eFType );
     352             282 :         if ( EQUALN(oField.GetNameRef(), "ogr:", 4) )
     353               0 :             oField.SetName(poProperty->GetName()+4);
     354             282 :         if( poProperty->GetWidth() > 0 )
     355               0 :             oField.SetWidth( poProperty->GetWidth() );
     356             282 :         if( poProperty->GetPrecision() > 0 )
     357               0 :             oField.SetPrecision( poProperty->GetPrecision() );
     358                 : 
     359             282 :         poFDefn->AddFieldDefn( &oField );
     360                 :     }
     361                 : 
     362              62 :     const char* pszGeometryColumnName = poGMLFeatureClass->GetGeometryElement();
     363              62 :     if (pszGeometryColumnName)
     364              62 :         osGeometryColumnName = pszGeometryColumnName;
     365                 : 
     366              62 :     return poFDefn;
     367                 : }
     368                 : 
     369                 : /************************************************************************/
     370                 : /*                       MakeGetFeatureURL()                            */
     371                 : /************************************************************************/
     372                 : 
     373              54 : CPLString OGRWFSLayer::MakeGetFeatureURL(int nMaxFeatures, int bRequestHits)
     374                 : {
     375              54 :     CPLString osURL(pszBaseURL);
     376              54 :     osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
     377              54 :     osURL = CPLURLAddKVP(osURL, "VERSION", poDS->GetVersion());
     378              54 :     osURL = CPLURLAddKVP(osURL, "REQUEST", "GetFeature");
     379              54 :     osURL = CPLURLAddKVP(osURL, "TYPENAME", WFS_EscapeURL(pszName));
     380              54 :     if (pszRequiredOutputFormat)
     381               2 :         osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", WFS_EscapeURL(pszRequiredOutputFormat));
     382                 : 
     383              54 :     if (poDS->IsPagingAllowed() && !bRequestHits)
     384                 :     {
     385               0 :         if (nFeatures < 0)
     386                 :         {
     387               0 :             if ((m_poAttrQuery == NULL || osWFSWhere.size() != 0) &&
     388                 :                 poDS->GetFeatureSupportHits())
     389                 :             {
     390               0 :                 nFeatures = ExecuteGetFeatureResultTypeHits();
     391                 :             }
     392                 :         }
     393               0 :         if (nFeatures >= poDS->GetPageSize())
     394                 :         {
     395               0 :             osURL = CPLURLAddKVP(osURL, "STARTINDEX", CPLSPrintf("%d", nPagingStartIndex + 1));
     396               0 :             nMaxFeatures = poDS->GetPageSize();
     397               0 :             nFeatureCountRequested = nMaxFeatures;
     398               0 :             bPagingActive = TRUE;
     399                 :         }
     400                 :         else
     401                 :         {
     402               0 :             osURL = CPLURLAddKVP(osURL, "STARTINDEX", NULL);
     403                 :         }
     404                 :     }
     405                 : 
     406              54 :     if (nMaxFeatures)
     407                 :     {
     408                 :         osURL = CPLURLAddKVP(osURL,
     409                 :                              atoi(poDS->GetVersion()) >= 2 ? "COUNT" : "MAXFEATURES",
     410               0 :                              CPLSPrintf("%d", nMaxFeatures));
     411                 :     }
     412              54 :     if (pszNS && poDS->GetNeedNAMESPACE())
     413                 :     {
     414                 :         /* Older Deegree version require NAMESPACE (e.g. http://www.nokis.org/deegree2/ogcwebservice) */
     415                 :         /* This has been now corrected */
     416               0 :         CPLString osValue("xmlns(");
     417               0 :         osValue += pszNS;
     418               0 :         osValue += "=";
     419               0 :         osValue += pszNSVal;
     420               0 :         osValue += ")";
     421               0 :         osURL = CPLURLAddKVP(osURL, "NAMESPACE", WFS_EscapeURL(osValue));
     422                 :     }
     423                 : 
     424              54 :     delete poFetchedFilterGeom;
     425              54 :     poFetchedFilterGeom = NULL;
     426                 : 
     427              54 :     CPLString osGeomFilter;
     428                 : 
     429              54 :     if (m_poFilterGeom != NULL && osGeometryColumnName.size() > 0)
     430                 :     {
     431               5 :         OGREnvelope oEnvelope;
     432               5 :         m_poFilterGeom->getEnvelope(&oEnvelope);
     433                 : 
     434               5 :         poFetchedFilterGeom = m_poFilterGeom->clone();
     435                 : 
     436               5 :         osGeomFilter = "<BBOX>";
     437               5 :         if (atoi(poDS->GetVersion()) >= 2)
     438               1 :             osGeomFilter += "<ValueReference>";
     439                 :         else
     440               4 :             osGeomFilter += "<PropertyName>";
     441               5 :         if (pszNS)
     442                 :         {
     443               4 :             osGeomFilter += pszNS;
     444               4 :             osGeomFilter += ":";
     445                 :         }
     446               5 :         osGeomFilter += osGeometryColumnName;
     447               5 :         if (atoi(poDS->GetVersion()) >= 2)
     448               1 :             osGeomFilter += "</ValueReference>";
     449                 :         else
     450               4 :             osGeomFilter += "</PropertyName>";
     451                 : 
     452               5 :         CPLLocaleC  oLocaleEnforcer;
     453                 : 
     454               5 :         if ( atoi(poDS->GetVersion()) >= 2 )
     455                 :         {
     456               1 :             osGeomFilter += "<gml:Envelope";
     457                 : 
     458               1 :             CPLString osSRSName = CPLURLGetValue(pszBaseURL, "SRSNAME");
     459               1 :             if( osSRSName.size() )
     460                 :             {
     461               0 :                 osGeomFilter += " srsName=\"";
     462               0 :                 osGeomFilter += osSRSName;
     463               0 :                 osGeomFilter += "\"";
     464                 :             }
     465                 : 
     466               1 :             osGeomFilter += ">";
     467               1 :             if (bAxisOrderAlreadyInverted)
     468                 :             {
     469                 :                 osGeomFilter += CPLSPrintf("<gml:lowerCorner>%.16f %.16f</gml:lowerCorner><gml:upperCorner>%.16f %.16f</gml:upperCorner>",
     470               0 :                                         oEnvelope.MinY, oEnvelope.MinX, oEnvelope.MaxY, oEnvelope.MaxX);
     471                 :             }
     472                 :             else
     473                 :                 osGeomFilter += CPLSPrintf("<gml:lowerCorner>%.16f %.16f</gml:lowerCorner><gml:upperCorner>%.16f %.16f</gml:upperCorner>",
     474               1 :                                         oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, oEnvelope.MaxY);
     475               1 :             osGeomFilter += "</gml:Envelope>";
     476                 :         }
     477               4 :         else if ( poDS->RequiresEnvelopeSpatialFilter() )
     478                 :         {
     479               0 :             osGeomFilter += "<Envelope xmlns=\"http://www.opengis.net/gml\">";
     480               0 :             if (bAxisOrderAlreadyInverted)
     481                 :             {
     482                 :                 /* We can go here in WFS 1.1 with geographic coordinate systems */
     483                 :                 /* that are natively return in lat,long order, but as we have */
     484                 :                 /* presented long,lat order to the user, we must switch back */
     485                 :                 /* for the server... */
     486                 :                 osGeomFilter += CPLSPrintf("<coord><X>%.16f</X><Y>%.16f</Y></coord><coord><X>%.16f</X><Y>%.16f</Y></coord>",
     487               0 :                                         oEnvelope.MinY, oEnvelope.MinX, oEnvelope.MaxY, oEnvelope.MaxX);
     488                 :             }
     489                 :             else
     490                 :                 osGeomFilter += CPLSPrintf("<coord><X>%.16f</X><Y>%.16f</Y></coord><coord><X>%.16f</X><Y>%.16f</Y></coord>",
     491               0 :                                         oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, oEnvelope.MaxY);
     492               0 :             osGeomFilter += "</Envelope>";
     493                 :         }
     494                 :         else
     495                 :         {
     496               4 :             osGeomFilter += "<gml:Box>";
     497               4 :             osGeomFilter += "<gml:coordinates>";
     498               4 :             if (bAxisOrderAlreadyInverted)
     499                 :             {
     500                 :                 /* We can go here in WFS 1.1 with geographic coordinate systems */
     501                 :                 /* that are natively return in lat,long order, but as we have */
     502                 :                 /* presented long,lat order to the user, we must switch back */
     503                 :                 /* for the server... */
     504               0 :                 osGeomFilter += CPLSPrintf("%.16f,%.16f %.16f,%.16f", oEnvelope.MinY, oEnvelope.MinX, oEnvelope.MaxY, oEnvelope.MaxX);
     505                 :             }
     506                 :             else
     507               4 :                 osGeomFilter += CPLSPrintf("%.16f,%.16f %.16f,%.16f", oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, oEnvelope.MaxY);
     508               4 :             osGeomFilter += "</gml:coordinates>";
     509               4 :             osGeomFilter += "</gml:Box>";
     510                 :         }
     511               5 :         osGeomFilter += "</BBOX>";
     512                 :     }
     513                 : 
     514              54 :     if (osGeomFilter.size() != 0 || osWFSWhere.size() != 0)
     515                 :     {
     516              21 :         CPLString osFilter;
     517              21 :         if (atoi(poDS->GetVersion()) >= 2)
     518               8 :             osFilter = "<Filter xmlns=\"http://www.opengis.net/fes/2.0\"";
     519                 :         else
     520              13 :             osFilter = "<Filter xmlns=\"http://www.opengis.net/ogc\"";
     521              21 :         if (pszNS)
     522                 :         {
     523              15 :             osFilter += " xmlns:";
     524              15 :             osFilter += pszNS;
     525              15 :             osFilter += "=\"";
     526              15 :             osFilter += pszNSVal;
     527              15 :             osFilter += "\"";
     528                 :         }
     529              21 :         if (atoi(poDS->GetVersion()) >= 2)
     530               8 :             osFilter += " xmlns:gml=\"http://www.opengis.net/gml/3.2\">";
     531                 :         else
     532              13 :             osFilter += " xmlns:gml=\"http://www.opengis.net/gml\">";
     533              21 :         if (osGeomFilter.size() != 0 && osWFSWhere.size() != 0)
     534               0 :             osFilter += "<And>";
     535              21 :         osFilter += osWFSWhere;
     536              21 :         osFilter += osGeomFilter;
     537              21 :         if (osGeomFilter.size() != 0 && osWFSWhere.size() != 0)
     538               0 :             osFilter += "</And>";
     539              21 :         osFilter += "</Filter>";
     540                 : 
     541              21 :         osURL = CPLURLAddKVP(osURL, "FILTER", WFS_EscapeURL(osFilter));
     542                 :     }
     543                 :         
     544              54 :     if (bRequestHits)
     545                 :     {
     546              10 :         osURL = CPLURLAddKVP(osURL, "RESULTTYPE", "hits");
     547                 :     }
     548              44 :     else if (osFieldToSort.size() != 0)
     549                 :     {
     550               3 :         CPLString osSortBy(osFieldToSort);
     551               3 :         if (!bAscFlag)
     552                 :         {
     553               3 :             if (atoi(poDS->GetVersion()) >= 2)
     554               3 :                 osSortBy += " DESC";
     555                 :             else
     556               0 :                 osSortBy += " D";
     557                 :         }
     558               3 :         osURL = CPLURLAddKVP(osURL, "SORTBY", WFS_EscapeURL(osSortBy));
     559                 :     }
     560                 : 
     561                 :     /* If no PROPERTYNAME is specified, build one if there are ignored fields */
     562              54 :     CPLString osPropertyName = CPLURLGetValue(osURL, "PROPERTYNAME");
     563              54 :     const char* pszPropertyName = osPropertyName.c_str();
     564              54 :     if (pszPropertyName[0] == 0 && poFeatureDefn != NULL)
     565                 :     {
     566              50 :         int bHasIgnoredField = FALSE;
     567              50 :         CPLString osPropertyName;
     568             382 :         for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     569                 :         {
     570             332 :             if (EQUAL(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), "gml_id"))
     571                 :             {
     572                 :                 /* fake field : skip it */
     573                 :             }
     574             282 :             else if (poFeatureDefn->GetFieldDefn(iField)->IsIgnored())
     575                 :             {
     576               8 :                 bHasIgnoredField = TRUE;
     577                 :             }
     578                 :             else
     579                 :             {
     580             274 :                 if (osPropertyName.size() != 0)
     581             227 :                     osPropertyName += ",";
     582             274 :                 osPropertyName += poFeatureDefn->GetFieldDefn(iField)->GetNameRef();
     583                 :             }
     584                 :         }
     585              50 :         if (osGeometryColumnName.size() != 0)
     586                 :         {
     587              47 :             if (poFeatureDefn->IsGeometryIgnored())
     588                 :             {
     589               2 :                 bHasIgnoredField = TRUE;
     590                 :             }
     591                 :             else
     592                 :             {
     593              45 :                 if (osPropertyName.size() != 0)
     594              44 :                     osPropertyName += ",";
     595              45 :                 osPropertyName += osGeometryColumnName;
     596                 :             }
     597                 :         }
     598                 : 
     599              50 :         if (bHasIgnoredField && osPropertyName.size())
     600                 :         {
     601               0 :             osPropertyName = "(" + osPropertyName + ")";
     602               0 :             osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", WFS_EscapeURL(osPropertyName));
     603              50 :         }
     604                 :     }
     605                 : 
     606              54 :     return osURL;
     607                 : }
     608                 : 
     609                 : 
     610                 : /************************************************************************/
     611                 : /*               OGRWFSFetchContentDispositionFilename()                */
     612                 : /************************************************************************/
     613                 : 
     614               7 : const char* OGRWFSFetchContentDispositionFilename(char** papszHeaders)
     615                 : {
     616               7 :     char** papszIter = papszHeaders;
     617              54 :     while(papszIter && *papszIter)
     618                 :     {
     619                 :         /* For multipart, we have in raw format, but without end-of-line characters */
     620              41 :         if (strncmp(*papszIter, "Content-Disposition: attachment; filename=", 42) == 0)
     621                 :         {
     622               0 :             return *papszIter + 42;
     623                 :         }
     624                 :         /* For single part, the headers are in KEY=VAL format, but with e-o-l ... */
     625              41 :         else if (strncmp(*papszIter, "Content-Disposition=attachment; filename=", 41) == 0)
     626                 :         {
     627               1 :             char* pszVal = (char*)(*papszIter + 41);
     628               1 :             char* pszEOL = strchr(pszVal, '\r');
     629               1 :             if (pszEOL) *pszEOL = 0;
     630               1 :             pszEOL = strchr(pszVal, '\n');
     631               1 :             if (pszEOL) *pszEOL = 0;
     632               1 :             return pszVal;
     633                 :         }
     634              40 :         papszIter ++;
     635                 :     }
     636               6 :     return NULL;
     637                 : }
     638                 : 
     639                 : /************************************************************************/
     640                 : /*                  MustRetryIfNonCompliantServer()                     */
     641                 : /************************************************************************/
     642                 : 
     643               9 : int OGRWFSLayer::MustRetryIfNonCompliantServer(const char* pszServerAnswer)
     644                 : {
     645               9 :     int bRetry = FALSE;
     646                 : 
     647                 :     /* Deegree server does not support PropertyIsNotEqualTo */
     648                 :     /* We have to turn it into <Not><PropertyIsEqualTo> */
     649               9 :     if (osWFSWhere.size() != 0 && poDS->PropertyIsNotEqualToSupported() &&
     650                 :         strstr(pszServerAnswer, "Unknown comparison operation: 'PropertyIsNotEqualTo'") != NULL)
     651                 :     {
     652               2 :         poDS->SetPropertyIsNotEqualToUnSupported();
     653               2 :         bRetry = TRUE;
     654                 :     }
     655                 : 
     656                 :     /* Deegree server requires the gml: prefix in GmlObjectId element, but ESRI */
     657                 :     /* doesn't like it at all ! Other servers don't care... */
     658               9 :     if (osWFSWhere.size() != 0 && !poDS->DoesGmlObjectIdNeedGMLPrefix() &&
     659                 :         strstr(pszServerAnswer, "&lt;GmlObjectId&gt; requires 'gml:id'-attribute!") != NULL)
     660                 :     {
     661               0 :         poDS->SetGmlObjectIdNeedsGMLPrefix();
     662               0 :         bRetry = TRUE;
     663                 :     }
     664                 : 
     665                 :     /* GeoServer can return the error 'Only FeatureIds are supported when encoding id filters to SDE' */
     666               9 :     if (osWFSWhere.size() != 0 && !bUseFeatureIdAtLayerLevel &&
     667                 :         strstr(pszServerAnswer, "Only FeatureIds are supported") != NULL)
     668                 :     {
     669               0 :         bUseFeatureIdAtLayerLevel = TRUE;
     670               0 :         bRetry = TRUE;
     671                 :     }
     672                 : 
     673               9 :     if (bRetry)
     674                 :     {
     675               2 :         SetAttributeFilter(osSQLWhere);
     676               2 :         bHasFetched = TRUE;
     677               2 :         bReloadNeeded = FALSE;
     678                 :     }
     679                 : 
     680               9 :     return bRetry;
     681                 : }
     682                 : 
     683                 : /************************************************************************/
     684                 : /*                         FetchGetFeature()                            */
     685                 : /************************************************************************/
     686                 : 
     687              44 : OGRDataSource* OGRWFSLayer::FetchGetFeature(int nMaxFeatures)
     688                 : {
     689                 : 
     690              44 :     CPLString osURL = MakeGetFeatureURL(nMaxFeatures, FALSE);
     691              44 :     CPLDebug("WFS", "%s", osURL.c_str());
     692                 : 
     693              44 :     CPLHTTPResult* psResult = NULL;
     694                 : 
     695              44 :     CPLString osOutputFormat = CPLURLGetValue(osURL, "OUTPUTFORMAT");
     696                 : 
     697                 :     /* Try streaming when the output format is GML and that we have a .xsd */
     698                 :     /* that we are able to understand */
     699              44 :     CPLString osXSDFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
     700                 :     VSIStatBufL sBuf;
     701              44 :     OGRSFDriverH hGMLDrv = OGRGetDriverByName("GML");
     702              44 :     if (CSLTestBoolean(CPLGetConfigOption("OGR_WFS_USE_STREAMING", "YES")) &&
     703                 :         (osOutputFormat.size() == 0 || osOutputFormat.ifind("GML") != std::string::npos) &&
     704                 :         VSIStatL(osXSDFileName, &sBuf) == 0 && hGMLDrv != NULL)
     705                 :     {
     706                 :         const char* pszStreamingName = CPLSPrintf("/vsicurl_streaming/%s",
     707              38 :                                                     osURL.c_str());
     708                 :         const char* pszStreamingNameWithXSD = CPLSPrintf("%s,xsd=%s",
     709              38 :                                             pszStreamingName, osXSDFileName.c_str());
     710                 :         OGRDataSource* poGML_DS = (OGRDataSource*)
     711              38 :                 OGR_Dr_Open(hGMLDrv, pszStreamingNameWithXSD, FALSE);
     712              38 :         if (poGML_DS)
     713                 :         {
     714              36 :             bStreamingDS = TRUE;
     715              36 :             return poGML_DS;
     716                 :         }
     717                 : 
     718                 :         /* In case of failure, read directly the content to examine */
     719                 :         /* it, if it is XML error content */
     720                 :         char szBuffer[2048];
     721               2 :         int nRead = 0;
     722               2 :         VSILFILE* fp = VSIFOpenL(pszStreamingName, "rb");
     723               2 :         if (fp)
     724                 :         {
     725               2 :             nRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
     726               2 :             szBuffer[nRead] = '\0';
     727               2 :             VSIFCloseL(fp);
     728                 :         }
     729                 : 
     730               2 :         if (nRead != 0)
     731                 :         {
     732               2 :             if (MustRetryIfNonCompliantServer(szBuffer))
     733               1 :                 return FetchGetFeature(nMaxFeatures);
     734                 : 
     735               1 :             if (strstr(szBuffer, "<ServiceExceptionReport") != NULL ||
     736                 :                 strstr(szBuffer, "<ows:ExceptionReport") != NULL)
     737                 :             {
     738               0 :                 if (poDS->IsOldDeegree(szBuffer))
     739                 :                 {
     740               0 :                     return FetchGetFeature(nMaxFeatures);
     741                 :                 }
     742                 : 
     743                 :                 CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
     744               0 :                             szBuffer);
     745               0 :                 return NULL;
     746                 :             }
     747                 :         }
     748                 :     }
     749                 : 
     750               7 :     bStreamingDS = FALSE;
     751               7 :     psResult = poDS->HTTPFetch( osURL, NULL);
     752               7 :     if (psResult == NULL)
     753                 :     {
     754               0 :         return NULL;
     755                 :     }
     756                 : 
     757               7 :     const char* pszContentType = "";
     758               7 :     if (psResult->pszContentType)
     759               7 :         pszContentType = psResult->pszContentType;
     760                 : 
     761               7 :     CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
     762               7 :     VSIMkdir(osTmpDirName, 0);
     763                 : 
     764               7 :     GByte *pabyData = psResult->pabyData;
     765               7 :     int    nDataLen = psResult->nDataLen;
     766               7 :     int bIsMultiPart = FALSE;
     767               7 :     const char* pszAttachementFilename = NULL;
     768                 : 
     769               7 :     if(strstr(pszContentType,"multipart")
     770                 :         && CPLHTTPParseMultipartMime(psResult) )
     771                 :     {
     772                 :         int i;
     773               0 :         bIsMultiPart = TRUE;
     774               0 :         OGRWFSRecursiveUnlink(osTmpDirName);
     775               0 :         VSIMkdir(osTmpDirName, 0);
     776               0 :         for(i=0;i<psResult->nMimePartCount;i++)
     777                 :         {
     778               0 :             CPLString osTmpFileName = osTmpDirName + "/";
     779                 :             pszAttachementFilename =
     780                 :                 OGRWFSFetchContentDispositionFilename(
     781               0 :                     psResult->pasMimePart[i].papszHeaders);
     782                 : 
     783               0 :             if (pszAttachementFilename)
     784               0 :                 osTmpFileName += pszAttachementFilename;
     785                 :             else
     786               0 :                 osTmpFileName += CPLSPrintf("file_%d", i);
     787                 : 
     788               0 :             GByte* pData = (GByte*)VSIMalloc(psResult->pasMimePart[i].nDataLen);
     789               0 :             if (pData)
     790                 :             {
     791               0 :                 memcpy(pData, psResult->pasMimePart[i].pabyData, psResult->pasMimePart[i].nDataLen);
     792                 :                 VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName,
     793                 :                                                 pData,
     794               0 :                                                 psResult->pasMimePart[i].nDataLen, TRUE);
     795               0 :                 VSIFCloseL(fp);
     796                 :             }
     797                 :         }
     798                 :     }
     799                 :     else
     800                 :         pszAttachementFilename =
     801                 :                 OGRWFSFetchContentDispositionFilename(
     802               7 :                     psResult->papszHeaders);
     803                 : 
     804               7 :     int bJSON = FALSE;
     805               7 :     int bCSV = FALSE;
     806               7 :     int bKML = FALSE;
     807               7 :     int bKMZ = FALSE;
     808               7 :     int bZIP = FALSE;
     809               7 :     int bGZIP = FALSE;
     810                 : 
     811               7 :     const char* pszOutputFormat = osOutputFormat.c_str();
     812                 : 
     813               7 :     if (FindSubStringInsensitive(pszContentType, "json") ||
     814                 :         FindSubStringInsensitive(pszOutputFormat, "json"))
     815                 :     {
     816               1 :         bJSON = TRUE;
     817                 :     }
     818               6 :     else if (FindSubStringInsensitive(pszContentType, "csv") ||
     819                 :              FindSubStringInsensitive(pszOutputFormat, "csv"))
     820                 :     {
     821               0 :         bCSV = TRUE;
     822                 :     }
     823               6 :     else if (FindSubStringInsensitive(pszContentType, "kml") ||
     824                 :              FindSubStringInsensitive(pszOutputFormat, "kml"))
     825                 :     {
     826               0 :         bKML = TRUE;
     827                 :     }
     828               6 :     else if (FindSubStringInsensitive(pszContentType, "kmz") ||
     829                 :              FindSubStringInsensitive(pszOutputFormat, "kmz"))
     830                 :     {
     831               0 :         bKMZ = TRUE;
     832                 :     }
     833               6 :     else if (strstr(pszContentType, "application/zip") != NULL)
     834                 :     {
     835               1 :         bZIP = TRUE;
     836                 :     }
     837               5 :     else if (strstr(pszContentType, "application/gzip") != NULL)
     838                 :     {
     839               0 :         bGZIP = TRUE;
     840                 :     }
     841                 : 
     842               7 :     if (MustRetryIfNonCompliantServer((const char*)pabyData))
     843                 :     {
     844               1 :         CPLHTTPDestroyResult(psResult);
     845               1 :         return FetchGetFeature(nMaxFeatures);
     846                 :     }
     847                 : 
     848               6 :     if (strstr((const char*)pabyData, "<ServiceExceptionReport") != NULL ||
     849                 :         strstr((const char*)pabyData, "<ows:ExceptionReport") != NULL)
     850                 :     {
     851               0 :         if (poDS->IsOldDeegree((const char*)pabyData))
     852                 :         {
     853               0 :             CPLHTTPDestroyResult(psResult);
     854               0 :             return FetchGetFeature(nMaxFeatures);
     855                 :         }
     856                 : 
     857                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
     858               0 :                  pabyData);
     859               0 :         CPLHTTPDestroyResult(psResult);
     860               0 :         return NULL;
     861                 :     }
     862                 : 
     863               6 :     CPLString osTmpFileName;
     864                 : 
     865               6 :     if (!bIsMultiPart)
     866                 :     {
     867               6 :         if (bJSON)
     868               1 :             osTmpFileName = osTmpDirName + "/file.geojson";
     869               5 :         else if (bZIP)
     870               1 :             osTmpFileName = osTmpDirName + "/file.zip";
     871               4 :         else if (bCSV)
     872               0 :             osTmpFileName = osTmpDirName + "/file.csv";
     873               4 :         else if (bKML)
     874               0 :             osTmpFileName = osTmpDirName + "/file.kml";
     875               4 :         else if (bKMZ)
     876               0 :             osTmpFileName = osTmpDirName + "/file.kmz";
     877                 :         /* GML is a special case. It needs the .xsd file that has been saved */
     878                 :         /* as file.xsd, so we cannot used the attachement filename */
     879               4 :         else if (pszAttachementFilename &&
     880                 :                  !EQUAL(CPLGetExtension(pszAttachementFilename), "GML"))
     881                 :         {
     882               0 :             osTmpFileName = osTmpDirName + "/";
     883               0 :             osTmpFileName += pszAttachementFilename;
     884                 :         }
     885                 :         else
     886                 :         {
     887               4 :             osTmpFileName = osTmpDirName + "/file.gfs";
     888               4 :             VSIUnlink(osTmpFileName);
     889                 : 
     890               4 :             osTmpFileName = osTmpDirName + "/file.gml";
     891                 :         }
     892                 : 
     893                 :         VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, pabyData,
     894               6 :                                         nDataLen, TRUE);
     895               6 :         VSIFCloseL(fp);
     896               6 :         psResult->pabyData = NULL;
     897                 : 
     898               6 :         if (bZIP)
     899                 :         {
     900               1 :             osTmpFileName = "/vsizip/" + osTmpFileName;
     901                 :         }
     902               5 :         else if (bGZIP)
     903                 :         {
     904               0 :             osTmpFileName = "/vsigzip/" + osTmpFileName;
     905                 :         }
     906                 :     }
     907                 :     else
     908                 :     {
     909               0 :         pabyData = NULL;
     910               0 :         nDataLen = 0;
     911               0 :         osTmpFileName = osTmpDirName;
     912                 :     }
     913                 : 
     914               6 :     CPLHTTPDestroyResult(psResult);
     915                 : 
     916                 :     OGRDataSource* poDS;
     917                 : 
     918               6 :     poDS = (OGRDataSource*) OGROpen(osTmpFileName, FALSE, NULL);
     919               6 :     if (poDS == NULL && (bZIP || bIsMultiPart))
     920                 :     {
     921               0 :         char** papszFileList = VSIReadDir(osTmpFileName);
     922                 :         int i;
     923               0 :         for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
     924                 :         {
     925                 :             CPLString osFullFilename =
     926               0 :                     CPLFormFilename( osTmpFileName, papszFileList[i], NULL );
     927               0 :             poDS = (OGRDataSource*) OGROpen(osFullFilename, FALSE, NULL);
     928               0 :             if (poDS != NULL)
     929                 :                 break;
     930                 :         }
     931                 : 
     932               0 :         CSLDestroy( papszFileList );
     933                 :     }
     934                 : 
     935               6 :     if (poDS == NULL)
     936                 :     {
     937               1 :         if (pabyData != NULL && !bJSON && !bZIP &&
     938                 :             strstr((const char*)pabyData, "<wfs:FeatureCollection") == NULL &&
     939                 :             strstr((const char*)pabyData, "<gml:FeatureCollection") == NULL)
     940                 :         {
     941               0 :             if (nDataLen > 1000)
     942               0 :                 pabyData[1000] = 0;
     943                 :             CPLError(CE_Failure, CPLE_AppDefined,
     944               0 :                     "Error: cannot parse %s", pabyData);
     945                 :         }
     946               1 :         return NULL;
     947                 :     }
     948                 : 
     949               5 :     OGRLayer* poLayer = poDS->GetLayer(0);
     950               5 :     if (poLayer == NULL)
     951                 :     {
     952               0 :         OGRDataSource::DestroyDataSource(poDS);
     953               0 :         return NULL;
     954                 :     }
     955                 : 
     956               5 :     return poDS;
     957                 : }
     958                 : 
     959                 : /************************************************************************/
     960                 : /*                            GetLayerDefn()                            */
     961                 : /************************************************************************/
     962                 : 
     963            2620 : OGRFeatureDefn * OGRWFSLayer::GetLayerDefn()
     964                 : {
     965            2620 :     if (poFeatureDefn)
     966            2602 :         return poFeatureDefn;
     967                 : 
     968              18 :     poDS->LoadMultipleLayerDefn(GetName(), pszNS, pszNSVal);
     969                 : 
     970              18 :     if (poFeatureDefn)
     971              11 :         return poFeatureDefn;
     972                 : 
     973               7 :     return BuildLayerDefn();
     974                 : }
     975                 : 
     976                 : /************************************************************************/
     977                 : /*                          BuildLayerDefn()                            */
     978                 : /************************************************************************/
     979                 : 
     980              62 : OGRFeatureDefn * OGRWFSLayer::BuildLayerDefn(OGRFeatureDefn* poSrcFDefn)
     981                 : {
     982              62 :     int bUnsetWidthPrecision = FALSE;
     983                 : 
     984              62 :     poFeatureDefn = new OGRFeatureDefn( pszName );
     985              62 :     poFeatureDefn->Reference();
     986                 : 
     987              62 :     OGRDataSource* poDS = NULL;
     988                 : 
     989              62 :     if (poSrcFDefn == NULL)
     990               7 :         poSrcFDefn = DescribeFeatureType();
     991              62 :     if (poSrcFDefn == NULL)
     992                 :     {
     993               0 :         poDS = FetchGetFeature(1);
     994               0 :         if (poDS == NULL)
     995                 :         {
     996               0 :             return poFeatureDefn;
     997                 :         }
     998               0 :         poSrcFDefn = poDS->GetLayer(0)->GetLayerDefn();
     999               0 :         bGotApproximateLayerDefn = TRUE;
    1000                 :         /* We cannot trust width and precision based on a single feature */
    1001               0 :         bUnsetWidthPrecision = TRUE;
    1002                 :     }
    1003                 : 
    1004              62 :     CPLString osPropertyName = CPLURLGetValue(pszBaseURL, "PROPERTYNAME");
    1005              62 :     const char* pszPropertyName = osPropertyName.c_str();
    1006                 : 
    1007                 :     int i;
    1008              62 :     poFeatureDefn->SetGeomType(poSrcFDefn->GetGeomType());
    1009             406 :     for(i=0;i<poSrcFDefn->GetFieldCount();i++)
    1010                 :     {
    1011             344 :         if (pszPropertyName[0] != 0)
    1012                 :         {
    1013               0 :             if (strstr(pszPropertyName,
    1014                 :                        poSrcFDefn->GetFieldDefn(i)->GetNameRef()) != NULL)
    1015               0 :                 poFeatureDefn->AddFieldDefn(poSrcFDefn->GetFieldDefn(i));
    1016                 :             else
    1017               0 :                 bGotApproximateLayerDefn = TRUE;
    1018                 :         }
    1019                 :         else
    1020                 :         {
    1021             344 :             OGRFieldDefn oFieldDefn(poSrcFDefn->GetFieldDefn(i));
    1022             344 :             if (bUnsetWidthPrecision)
    1023                 :             {
    1024               0 :                 oFieldDefn.SetWidth(0);
    1025               0 :                 oFieldDefn.SetPrecision(0);
    1026                 :             }
    1027             344 :             poFeatureDefn->AddFieldDefn(&oFieldDefn);
    1028                 :         }
    1029                 :     }
    1030                 : 
    1031              62 :     if (poDS)
    1032               0 :         OGRDataSource::DestroyDataSource(poDS);
    1033                 :     else
    1034              62 :         delete poSrcFDefn;
    1035                 : 
    1036              62 :     return poFeatureDefn;
    1037                 : }
    1038                 : 
    1039                 : /************************************************************************/
    1040                 : /*                           GetSpatialRef()                            */
    1041                 : /************************************************************************/
    1042                 : 
    1043               8 : OGRSpatialReference *OGRWFSLayer::GetSpatialRef()
    1044                 : {
    1045               8 :     GetLayerDefn();
    1046               8 :     return poSRS;
    1047                 : }
    1048                 : 
    1049                 : /************************************************************************/
    1050                 : /*                            ResetReading()                            */
    1051                 : /************************************************************************/
    1052                 : 
    1053             141 : void OGRWFSLayer::ResetReading()
    1054                 : 
    1055                 : {
    1056             141 :     GetLayerDefn();
    1057             141 :     if (bPagingActive)
    1058               0 :         bReloadNeeded = TRUE;
    1059             141 :     nPagingStartIndex = 0;
    1060             141 :     nFeatureRead = 0;
    1061             141 :     nFeatureCountRequested = 0;
    1062             141 :     if (bReloadNeeded)
    1063                 :     {
    1064              35 :         OGRDataSource::DestroyDataSource(poBaseDS);
    1065              35 :         poBaseDS = NULL;
    1066              35 :         poBaseLayer = NULL;
    1067              35 :         bHasFetched = FALSE;
    1068              35 :         bReloadNeeded = FALSE;
    1069                 :     }
    1070             141 :     if (poBaseLayer)
    1071              63 :         poBaseLayer->ResetReading();
    1072             141 : }
    1073                 : 
    1074                 : 
    1075                 : /************************************************************************/
    1076                 : /*                           GetNextFeature()                           */
    1077                 : /************************************************************************/
    1078                 : 
    1079             972 : OGRFeature *OGRWFSLayer::GetNextFeature()
    1080                 : {
    1081             972 :     GetLayerDefn();
    1082             972 :     if (bPagingActive && nFeatureRead == nPagingStartIndex + nFeatureCountRequested)
    1083                 :     {
    1084               0 :         bReloadNeeded = TRUE;
    1085               0 :         nPagingStartIndex = nFeatureRead;
    1086                 :     }
    1087             972 :     if (bReloadNeeded)
    1088                 :     {
    1089               4 :         OGRDataSource::DestroyDataSource(poBaseDS);
    1090               4 :         poBaseDS = NULL;
    1091               4 :         poBaseLayer = NULL;
    1092               4 :         bHasFetched = FALSE;
    1093               4 :         bReloadNeeded = FALSE;
    1094                 :     }
    1095             972 :     if (poBaseDS == NULL && !bHasFetched)
    1096                 :     {
    1097              42 :         bHasFetched = TRUE;
    1098              42 :         poBaseDS = FetchGetFeature(0);
    1099              42 :         if (poBaseDS)
    1100                 :         {
    1101              41 :             poBaseLayer = poBaseDS->GetLayer(0);
    1102              41 :             poBaseLayer->ResetReading();
    1103                 : 
    1104                 :             /* Check that the layer field definition is consistant with the one */
    1105                 :             /* we got in BuildLayerDefn() */
    1106              41 :             if (poFeatureDefn->GetFieldCount() != poBaseLayer->GetLayerDefn()->GetFieldCount())
    1107               1 :                 bGotApproximateLayerDefn = TRUE;
    1108                 :             else
    1109                 :             {
    1110                 :                 int iField;
    1111             267 :                 for(iField = 0;iField < poFeatureDefn->GetFieldCount(); iField++)
    1112                 :                 {
    1113             228 :                     OGRFieldDefn* poFDefn1 = poFeatureDefn->GetFieldDefn(iField);
    1114             228 :                     OGRFieldDefn* poFDefn2 = poBaseLayer->GetLayerDefn()->GetFieldDefn(iField);
    1115             228 :                     if (strcmp(poFDefn1->GetNameRef(), poFDefn2->GetNameRef()) != 0 ||
    1116                 :                         poFDefn1->GetType() != poFDefn2->GetType())
    1117                 :                     {
    1118               1 :                         bGotApproximateLayerDefn = TRUE;
    1119               1 :                         break;
    1120                 :                     }
    1121                 :                 }
    1122                 :             }
    1123                 :         }
    1124                 :     }
    1125             972 :     if (!poBaseLayer)
    1126               1 :         return NULL;
    1127                 : 
    1128              24 :     while(TRUE)
    1129                 :     {
    1130             995 :         OGRFeature* poSrcFeature = poBaseLayer->GetNextFeature();
    1131             995 :         if (poSrcFeature == NULL)
    1132              32 :             return NULL;
    1133             963 :         nFeatureRead ++;
    1134                 : 
    1135             963 :         OGRGeometry* poGeom = poSrcFeature->GetGeometryRef();
    1136             963 :         if( m_poFilterGeom != NULL && poGeom != NULL &&
    1137                 :             !FilterGeometry( poGeom ) )
    1138                 :         {
    1139               0 :             delete poSrcFeature;
    1140               0 :             continue;
    1141                 :         }
    1142                 : 
    1143                 :         /* Client-side attribue filtering with underlying layer defn */
    1144                 :         /* identical to exposed layer defn */
    1145             963 :         if( !bGotApproximateLayerDefn &&
    1146                 :             osWFSWhere.size() == 0 &&
    1147                 :             m_poAttrQuery != NULL &&
    1148                 :             !m_poAttrQuery->Evaluate( poSrcFeature ) )
    1149                 :         {
    1150              24 :             delete poSrcFeature;
    1151              24 :             continue;
    1152                 :         }
    1153                 : 
    1154             939 :         OGRFeature* poNewFeature = new OGRFeature(poFeatureDefn);
    1155             939 :         if (bGotApproximateLayerDefn)
    1156                 :         {
    1157               2 :             poNewFeature->SetFrom(poSrcFeature);
    1158                 : 
    1159                 :             /* Client-side attribue filtering */
    1160               2 :             if( m_poAttrQuery != NULL &&
    1161                 :                 osWFSWhere.size() == 0 &&
    1162                 :                 !m_poAttrQuery->Evaluate( poNewFeature ) )
    1163                 :             {
    1164               0 :                 delete poSrcFeature;
    1165               0 :                 delete poNewFeature;
    1166               0 :                 continue;
    1167                 :             }
    1168                 :         }
    1169                 :         else
    1170                 :         {
    1171                 :             int iField;
    1172           14252 :             for(iField = 0;iField < poFeatureDefn->GetFieldCount(); iField++)
    1173           13315 :                 poNewFeature->SetField( iField, poSrcFeature->GetRawFieldRef(iField) );
    1174             937 :             poNewFeature->SetStyleString(poSrcFeature->GetStyleString());
    1175             937 :             poNewFeature->SetGeometryDirectly(poSrcFeature->StealGeometry());
    1176                 :         }
    1177             939 :         poNewFeature->SetFID(poSrcFeature->GetFID());
    1178             939 :         poGeom = poNewFeature->GetGeometryRef();
    1179                 : 
    1180                 :         /* FIXME? I don't really know what we should do with WFS 1.1.0 */
    1181                 :         /* and non-GML format !!! I guess 50% WFS servers must do it wrong anyway */
    1182                 :         /* GeoServer does currently axis inversion for non GML output, but */
    1183                 :         /* apparently this is not correct : http://jira.codehaus.org/browse/GEOS-3657 */
    1184             947 :         if (bAxisOrderAlreadyInverted &&
    1185               8 :             strcmp(poBaseDS->GetDriver()->GetName(), "GML") != 0)
    1186                 :         {
    1187               2 :             poGeom->swapXY();
    1188                 :         }
    1189                 : 
    1190             939 :         if (poGeom && poSRS)
    1191             939 :             poGeom->assignSpatialReference(poSRS);
    1192             939 :         delete poSrcFeature;
    1193             939 :         return poNewFeature;
    1194                 :     }
    1195                 : }
    1196                 : 
    1197                 : /************************************************************************/
    1198                 : /*                         SetSpatialFilter()                           */
    1199                 : /************************************************************************/
    1200                 : 
    1201              24 : void OGRWFSLayer::SetSpatialFilter( OGRGeometry * poGeom )
    1202                 : {
    1203              24 :     if (bStreamingDS)
    1204              22 :         bReloadNeeded = TRUE;
    1205               2 :     else if (poFetchedFilterGeom == NULL && poBaseDS != NULL)
    1206                 :     {
    1207                 :         /* If there was no filter set, and that we set one */
    1208                 :         /* the new result set can only be a subset of the whole */
    1209                 :         /* so no need to reload from source */
    1210               0 :         bReloadNeeded = FALSE;
    1211                 :     }
    1212               2 :     else if (poFetchedFilterGeom != NULL && poGeom != NULL && poBaseDS != NULL)
    1213                 :     {
    1214               0 :         OGREnvelope oOldEnvelope, oNewEnvelope;
    1215               0 :         poFetchedFilterGeom->getEnvelope(&oOldEnvelope);
    1216               0 :         poGeom->getEnvelope(&oNewEnvelope);
    1217                 :         /* Optimization : we don't need to request the server */
    1218                 :         /* if the new BBOX is inside the old BBOX as we have */
    1219                 :         /* already all the features */
    1220               0 :         bReloadNeeded = ! oOldEnvelope.Contains(oNewEnvelope);
    1221                 :     }
    1222                 :     else
    1223               2 :         bReloadNeeded = TRUE;
    1224              24 :     nFeatures = -1;
    1225              24 :     OGRLayer::SetSpatialFilter(poGeom);
    1226              24 :     ResetReading();
    1227              24 : }
    1228                 : 
    1229                 : /************************************************************************/
    1230                 : /*                        SetAttributeFilter()                          */
    1231                 : /************************************************************************/
    1232                 : 
    1233              36 : OGRErr OGRWFSLayer::SetAttributeFilter( const char * pszFilter )
    1234                 : {
    1235              36 :     if (pszFilter != NULL && pszFilter[0] == 0)
    1236               5 :         pszFilter = NULL;
    1237                 : 
    1238              36 :     OGRErr eErr = OGRLayer::SetAttributeFilter(pszFilter);
    1239              36 :     if (eErr != CE_None)
    1240               0 :         return eErr;
    1241                 : 
    1242              36 :     CPLString osOldWFSWhere(osWFSWhere);
    1243              36 :     if (poDS->HasMinOperators() && pszFilter != NULL)
    1244                 :     {
    1245              17 :         int bNeedsNullCheck = FALSE;
    1246                 :         int nVersion = (strcmp(poDS->GetVersion(),"1.0.0") == 0) ? 100 :
    1247              17 :                        (atoi(poDS->GetVersion()) >= 2) ? 200 : 110;
    1248                 :         osWFSWhere = WFS_TurnSQLFilterToOGCFilter(pszFilter,
    1249              17 :                                                   GetLayerDefn(),
    1250                 :                                                   nVersion,
    1251                 :                                                   poDS->PropertyIsNotEqualToSupported(),
    1252                 :                                                   poDS->UseFeatureId() || bUseFeatureIdAtLayerLevel,
    1253                 :                                                   poDS->DoesGmlObjectIdNeedGMLPrefix(),
    1254              34 :                                                   &bNeedsNullCheck);
    1255              17 :         if (bNeedsNullCheck && !poDS->HasNullCheck())
    1256               0 :             osWFSWhere = "";
    1257              17 :         if (osWFSWhere.size() == 0)
    1258                 :         {
    1259               4 :             CPLDebug("WFS", "Using client-side only mode for filter \"%s\"", pszFilter);
    1260                 :         }
    1261                 :     }
    1262                 :     else
    1263              19 :         osWFSWhere = "";
    1264                 : 
    1265              36 :     osSQLWhere = (pszFilter) ? pszFilter : "";
    1266                 : 
    1267              36 :     if (osWFSWhere != osOldWFSWhere)
    1268              18 :         bReloadNeeded = TRUE;
    1269                 :     else
    1270              18 :         bReloadNeeded = FALSE;
    1271              36 :     nFeatures = -1;
    1272                 : 
    1273              36 :     return CE_None;
    1274                 : }
    1275                 : 
    1276                 : /************************************************************************/
    1277                 : /*                           TestCapability()                           */
    1278                 : /************************************************************************/
    1279                 : 
    1280              70 : int OGRWFSLayer::TestCapability( const char * pszCap )
    1281                 : 
    1282                 : {
    1283              70 :     if( EQUAL(pszCap,OLCFastFeatureCount) )
    1284                 :     {
    1285              43 :         if (nFeatures >= 0)
    1286               2 :             return TRUE;
    1287                 : 
    1288                 :         return poBaseLayer != NULL && m_poFilterGeom == NULL &&
    1289              41 :                m_poAttrQuery == NULL &&  poBaseLayer->TestCapability(pszCap);
    1290                 :     }
    1291                 : 
    1292              27 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
    1293                 :     {
    1294               2 :         if (bHasExtents)
    1295               0 :             return TRUE;
    1296                 : 
    1297                 :         return poBaseLayer != NULL &&
    1298               2 :                poBaseLayer->TestCapability(pszCap);
    1299                 :     }
    1300                 : 
    1301              25 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
    1302               2 :         return poBaseLayer != NULL && poBaseLayer->TestCapability(pszCap);
    1303                 : 
    1304              23 :     else if( EQUAL(pszCap, OLCSequentialWrite) ||
    1305                 :              EQUAL(pszCap, OLCDeleteFeature) ||
    1306                 :              EQUAL(pszCap, OLCRandomWrite) )
    1307                 :     {
    1308              13 :         GetLayerDefn();
    1309                 :         return poDS->SupportTransactions() && poDS->UpdateMode() &&
    1310              13 :                poFeatureDefn->GetFieldIndex("gml_id") == 0;
    1311                 :     }
    1312              10 :     else if ( EQUAL(pszCap, OLCTransactions) )
    1313                 :     {
    1314               2 :         return poDS->SupportTransactions() && poDS->UpdateMode();
    1315                 :     }
    1316               8 :     else if( EQUAL(pszCap,OLCIgnoreFields) )
    1317                 :     {
    1318               2 :         return poBaseDS == NULL;
    1319                 :     }
    1320                 : 
    1321               6 :     return FALSE;
    1322                 : }
    1323                 : 
    1324                 : /************************************************************************/
    1325                 : /*                  ExecuteGetFeatureResultTypeHits()                   */
    1326                 : /************************************************************************/
    1327                 : 
    1328              10 : int OGRWFSLayer::ExecuteGetFeatureResultTypeHits()
    1329                 : {
    1330              10 :     char* pabyData = NULL;
    1331              10 :     CPLString osURL = MakeGetFeatureURL(0, TRUE);
    1332              10 :     if (pszRequiredOutputFormat)
    1333               2 :         osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", WFS_EscapeURL(pszRequiredOutputFormat));
    1334              10 :     CPLDebug("WFS", "%s", osURL.c_str());
    1335                 : 
    1336              10 :     CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
    1337              10 :     if (psResult == NULL)
    1338                 :     {
    1339               0 :         return -1;
    1340                 :     }
    1341                 : 
    1342                 :     /* http://demo.snowflakesoftware.com:8080/Obstacle_AIXM_ZIP/GOPublisherWFS returns */
    1343                 :     /* zip content, including for RESULTTYPE=hits */
    1344              10 :     if (psResult->pszContentType != NULL &&
    1345                 :         strstr(psResult->pszContentType, "application/zip") != NULL)
    1346                 :     {
    1347               0 :         CPLString osTmpFileName;
    1348               0 :         osTmpFileName.Printf("/vsimem/wfstemphits_%p.zip", this);
    1349                 :         VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, psResult->pabyData,
    1350               0 :                                              psResult->nDataLen, FALSE);
    1351               0 :         VSIFCloseL(fp);
    1352                 : 
    1353               0 :         CPLString osZipTmpFileName("/vsizip/" + osTmpFileName);
    1354                 : 
    1355               0 :         char** papszDirContent = CPLReadDir(osZipTmpFileName);
    1356               0 :         if (CSLCount(papszDirContent) != 1)
    1357                 :         {
    1358                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1359               0 :                      "Cannot parse result of RESULTTYPE=hits request : more than one file in zip");
    1360               0 :             CSLDestroy(papszDirContent);
    1361               0 :             CPLHTTPDestroyResult(psResult);
    1362               0 :             VSIUnlink(osTmpFileName);
    1363               0 :             return -1;
    1364                 :         }
    1365                 : 
    1366               0 :         CPLString osFileInZipTmpFileName = osZipTmpFileName + "/";
    1367               0 :         osFileInZipTmpFileName += papszDirContent[0];
    1368                 : 
    1369               0 :         fp = VSIFOpenL(osFileInZipTmpFileName.c_str(), "rb");
    1370               0 :         if (fp == NULL)
    1371                 :         {
    1372                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1373               0 :                      "Cannot parse result of RESULTTYPE=hits request : cannot open one file in zip");
    1374               0 :             CSLDestroy(papszDirContent);
    1375               0 :             CPLHTTPDestroyResult(psResult);
    1376               0 :             VSIUnlink(osTmpFileName);
    1377               0 :             return -1;
    1378                 :         }
    1379                 :         VSIStatBufL sBuf;
    1380               0 :         VSIStatL(osFileInZipTmpFileName.c_str(), &sBuf);
    1381               0 :         pabyData = (char*) CPLMalloc((size_t)(sBuf.st_size + 1));
    1382               0 :         pabyData[sBuf.st_size] = 0;
    1383               0 :         VSIFReadL(pabyData, 1, (size_t)sBuf.st_size, fp);
    1384               0 :         VSIFCloseL(fp);
    1385                 : 
    1386               0 :         CSLDestroy(papszDirContent);
    1387               0 :         VSIUnlink(osTmpFileName);
    1388                 :     }
    1389                 :     else
    1390                 :     {
    1391              10 :         pabyData = (char*) psResult->pabyData;
    1392              10 :         psResult->pabyData = NULL;
    1393                 :     }
    1394                 : 
    1395              10 :     if (strstr(pabyData, "<ServiceExceptionReport") != NULL ||
    1396                 :         strstr(pabyData, "<ows:ExceptionReport") != NULL)
    1397                 :     {
    1398               0 :         if (poDS->IsOldDeegree(pabyData))
    1399                 :         {
    1400               0 :             CPLHTTPDestroyResult(psResult);
    1401               0 :             return ExecuteGetFeatureResultTypeHits();
    1402                 :         }
    1403                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    1404               0 :                  pabyData);
    1405               0 :         CPLHTTPDestroyResult(psResult);
    1406               0 :         CPLFree(pabyData);
    1407               0 :         return -1;
    1408                 :     }
    1409                 : 
    1410              10 :     CPLXMLNode* psXML = CPLParseXMLString( pabyData );
    1411              10 :     if (psXML == NULL)
    1412                 :     {
    1413                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    1414               0 :                 pabyData);
    1415               0 :         CPLHTTPDestroyResult(psResult);
    1416               0 :         CPLFree(pabyData);
    1417               0 :         return -1;
    1418                 :     }
    1419                 : 
    1420              10 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
    1421              10 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=FeatureCollection" );
    1422              10 :     if (psRoot == NULL)
    1423                 :     {
    1424               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <FeatureCollection>");
    1425               0 :         CPLDestroyXMLNode( psXML );
    1426               0 :         CPLHTTPDestroyResult(psResult);
    1427               0 :         CPLFree(pabyData);
    1428               0 :         return -1;
    1429                 :     }
    1430                 : 
    1431              10 :     const char* pszValue = CPLGetXMLValue(psRoot, "numberOfFeatures", NULL);
    1432              10 :     if (pszValue == NULL)
    1433               6 :         pszValue = CPLGetXMLValue(psRoot, "numberMatched", NULL); /* WFS 2.0.0 */
    1434              10 :     if (pszValue == NULL)
    1435                 :     {
    1436               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find numberOfFeatures");
    1437               0 :         CPLDestroyXMLNode( psXML );
    1438               0 :         CPLHTTPDestroyResult(psResult);
    1439               0 :         CPLFree(pabyData);
    1440                 :         
    1441               0 :         poDS->DisableSupportHits();
    1442               0 :         return -1;
    1443                 :     }
    1444                 : 
    1445              10 :     int nFeatures = atoi(pszValue);
    1446                 :     /* Hum, http://deegree3-testing.deegree.org:80/deegree-inspire-node/services?MAXFEATURES=10&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=ad:Address&OUTPUTFORMAT=text/xml;%20subtype=gml/3.2.1&RESULTTYPE=hits */
    1447                 :     /* returns more than MAXFEATURES features... So truncate to MAXFEATURES */
    1448              10 :     CPLString osMaxFeatures = CPLURLGetValue(osURL, atoi(poDS->GetVersion()) >= 2 ? "COUNT" : "MAXFEATURES");
    1449              10 :     if (osMaxFeatures.size() != 0)
    1450                 :     {
    1451               4 :         int nMaxFeatures = atoi(osMaxFeatures);
    1452               4 :         if (nFeatures > nMaxFeatures)
    1453                 :         {
    1454               1 :             CPLDebug("WFS", "Truncating result from %d to %d", nFeatures, nMaxFeatures);
    1455               1 :             nFeatures = nMaxFeatures;
    1456                 :         }
    1457                 :     }
    1458                 : 
    1459              10 :     CPLDestroyXMLNode( psXML );
    1460              10 :     CPLHTTPDestroyResult(psResult);
    1461              10 :     CPLFree(pabyData);
    1462                 : 
    1463              10 :     return nFeatures;
    1464                 : }
    1465                 : 
    1466                 : /************************************************************************/
    1467                 : /*                           GetFeatureCount()                          */
    1468                 : /************************************************************************/
    1469                 : 
    1470              31 : int OGRWFSLayer::GetFeatureCount( int bForce )
    1471                 : {
    1472              31 :     if (nFeatures >= 0)
    1473               0 :         return nFeatures;
    1474                 : 
    1475              31 :     if (TestCapability(OLCFastFeatureCount))
    1476               4 :         return poBaseLayer->GetFeatureCount(bForce);
    1477                 : 
    1478              27 :     if ((m_poAttrQuery == NULL || osWFSWhere.size() != 0) &&
    1479                 :          poDS->GetFeatureSupportHits())
    1480                 :     {
    1481              10 :         nFeatures = ExecuteGetFeatureResultTypeHits();
    1482              10 :         if (nFeatures >= 0)
    1483               8 :             return nFeatures;
    1484                 :     }
    1485                 : 
    1486                 :     /* If we have not yet the base layer, try to read one */
    1487                 :     /* feature, and then query again OLCFastFeatureCount on the */
    1488                 :     /* base layer. In case the WFS response would contain the */
    1489                 :     /* number of features */
    1490              19 :     if (poBaseLayer == NULL)
    1491                 :     {
    1492               9 :         ResetReading();
    1493               9 :         OGRFeature* poFeature = GetNextFeature();
    1494               9 :         delete poFeature;
    1495               9 :         ResetReading();
    1496                 : 
    1497               9 :         if (TestCapability(OLCFastFeatureCount))
    1498               6 :             return poBaseLayer->GetFeatureCount(bForce);
    1499                 :     }
    1500                 : 
    1501              13 :     nFeatures = OGRLayer::GetFeatureCount(bForce);
    1502              13 :     return nFeatures;
    1503                 : }
    1504                 : 
    1505                 : 
    1506                 : /************************************************************************/
    1507                 : /*                              SetExtent()                             */
    1508                 : /************************************************************************/
    1509                 : 
    1510               0 : void OGRWFSLayer::SetExtents(double dfMinX, double dfMinY, double dfMaxX, double dfMaxY)
    1511                 : {
    1512               0 :     this->dfMinX = dfMinX;
    1513               0 :     this->dfMinY = dfMinY;
    1514               0 :     this->dfMaxX = dfMaxX;
    1515               0 :     this->dfMaxY = dfMaxY;
    1516               0 :     bHasExtents = TRUE;
    1517               0 : }
    1518                 : 
    1519                 : /************************************************************************/
    1520                 : /*                              GetExtent()                             */
    1521                 : /************************************************************************/
    1522                 : 
    1523               2 : OGRErr OGRWFSLayer::GetExtent(OGREnvelope *psExtent, int bForce)
    1524                 : {
    1525               2 :     if (bHasExtents)
    1526                 :     {
    1527               0 :         psExtent->MinX = dfMinX;
    1528               0 :         psExtent->MinY = dfMinY;
    1529               0 :         psExtent->MaxX = dfMaxX;
    1530               0 :         psExtent->MaxY = dfMaxY;
    1531               0 :         return OGRERR_NONE;
    1532                 :     }
    1533                 : 
    1534                 :     /* If we have not yet the base layer, try to read one */
    1535                 :     /* feature, and then query again OLCFastGetExtent on the */
    1536                 :     /* base layer. In case the WFS response would contain the */
    1537                 :     /* global extent */
    1538               2 :     if (poBaseLayer == NULL)
    1539                 :     {
    1540               2 :         ResetReading();
    1541               2 :         OGRFeature* poFeature = GetNextFeature();
    1542               2 :         delete poFeature;
    1543               2 :         ResetReading();
    1544                 :     }
    1545                 : 
    1546               2 :     if (TestCapability(OLCFastGetExtent))
    1547               2 :         return poBaseLayer->GetExtent(psExtent, bForce);
    1548                 : 
    1549               0 :     return OGRLayer::GetExtent(psExtent, bForce);
    1550                 : }
    1551                 : 
    1552                 : /************************************************************************/
    1553                 : /*                          GetShortName()                              */
    1554                 : /************************************************************************/
    1555                 : 
    1556            2146 : const char* OGRWFSLayer::GetShortName()
    1557                 : {
    1558            2146 :     const char* pszShortName = strchr(pszName, ':');
    1559            2146 :     if (pszShortName == NULL)
    1560              18 :         pszShortName = pszName;
    1561                 :     else
    1562            2128 :         pszShortName ++;
    1563            2146 :     return pszShortName;
    1564                 : }
    1565                 : 
    1566                 : 
    1567                 : /************************************************************************/
    1568                 : /*                          GetPostHeader()                             */
    1569                 : /************************************************************************/
    1570                 : 
    1571               5 : CPLString OGRWFSLayer::GetPostHeader()
    1572                 : {
    1573               5 :     CPLString osPost;
    1574               5 :     osPost += "<?xml version=\"1.0\"?>\n";
    1575               5 :     osPost += "<wfs:Transaction xmlns:wfs=\"http://www.opengis.net/wfs\"\n";
    1576               5 :     osPost += "                 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
    1577               5 :     osPost += "                 service=\"WFS\" version=\""; osPost += poDS->GetVersion(); osPost += "\"\n";
    1578               5 :     osPost += "                 xmlns:gml=\"http://www.opengis.net/gml\"\n";
    1579               5 :     osPost += "                 xmlns:ogc=\"http://www.opengis.net/ogc\"\n";
    1580               5 :     osPost += "                 xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/";
    1581               5 :     osPost += poDS->GetVersion();
    1582               5 :     osPost += "/wfs.xsd ";
    1583               5 :     osPost += osTargetNamespace;
    1584               5 :     osPost += " ";
    1585                 : 
    1586                 :     char* pszXMLEncoded = CPLEscapeString(
    1587               5 :                     GetDescribeFeatureTypeURL(FALSE), -1, CPLES_XML);
    1588               5 :     osPost += pszXMLEncoded;
    1589               5 :     CPLFree(pszXMLEncoded);
    1590                 : 
    1591               5 :     osPost += "\">\n";
    1592                 : 
    1593               0 :     return osPost;
    1594                 : }
    1595                 : 
    1596                 : /************************************************************************/
    1597                 : /*                          CreateFeature()                             */
    1598                 : /************************************************************************/
    1599                 : 
    1600               3 : OGRErr OGRWFSLayer::CreateFeature( OGRFeature *poFeature )
    1601                 : {
    1602               3 :     if (!TestCapability(OLCSequentialWrite))
    1603                 :     {
    1604               0 :         if (!poDS->SupportTransactions())
    1605                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1606               0 :                      "CreateFeature() not supported: no WMS-T features advertized by server");
    1607               0 :         else if (!poDS->UpdateMode())
    1608                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1609               0 :                      "CreateFeature() not supported: datasource opened as read-only");
    1610               0 :         return OGRERR_FAILURE;
    1611                 :     }
    1612                 : 
    1613               3 :     if (poGMLFeatureClass == NULL)
    1614                 :     {
    1615                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1616               0 :                  "Cannot insert feature because we didn't manage to parse the .XSD schema");
    1617               0 :         return OGRERR_FAILURE;
    1618                 :     }
    1619                 : 
    1620               3 :     if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
    1621                 :     {
    1622                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1623               0 :                  "Cannot find gml_id field");
    1624               0 :         return OGRERR_FAILURE;
    1625                 :     }
    1626                 : 
    1627               3 :     if (poFeature->IsFieldSet(0))
    1628                 :     {
    1629                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1630               0 :                  "Cannot insert a feature when gml_id field is already set");
    1631               0 :         return OGRERR_FAILURE;
    1632                 :     }
    1633                 : 
    1634               3 :     CPLString osPost;
    1635                 : 
    1636               3 :     const char* pszShortName = GetShortName();
    1637                 : 
    1638               3 :     if (!bInTransaction)
    1639                 :     {
    1640               1 :         osPost += GetPostHeader();
    1641               1 :         osPost += "  <wfs:Insert>\n";
    1642                 :     }
    1643               3 :     osPost += "    <feature:"; osPost += pszShortName; osPost += " xmlns:feature=\"";
    1644               3 :     osPost += osTargetNamespace; osPost += "\">\n";
    1645                 : 
    1646               3 :     CPLLocaleC  oLocaleEnforcer;
    1647                 : 
    1648                 :     int i;
    1649               6 :     for(i=1; i <= poFeature->GetFieldCount(); i++)
    1650                 :     {
    1651               6 :         if (poGMLFeatureClass->GetGeometryAttributeIndex() == i - 1)
    1652                 :         {
    1653               3 :             OGRGeometry* poGeom = poFeature->GetGeometryRef();
    1654               3 :             if (poGeom != NULL && osGeometryColumnName.size() != 0)
    1655                 :             {
    1656               3 :                 if (poGeom->getSpatialReference() == NULL)
    1657               3 :                     poGeom->assignSpatialReference(poSRS);
    1658                 :                 char* pszGML;
    1659               3 :                 if (strcmp(poDS->GetVersion(), "1.1.0") == 0)
    1660                 :                 {
    1661               3 :                     char** papszOptions = CSLAddString(NULL, "FORMAT=GML3");
    1662               3 :                     pszGML = OGR_G_ExportToGMLEx((OGRGeometryH)poGeom, papszOptions);
    1663               3 :                     CSLDestroy(papszOptions);
    1664                 :                 }
    1665                 :                 else
    1666               0 :                     pszGML = OGR_G_ExportToGML((OGRGeometryH)poGeom);
    1667               3 :                 osPost += "      <feature:"; osPost += osGeometryColumnName; osPost += ">";
    1668               3 :                 osPost += pszGML;
    1669               3 :                 osPost += "</feature:"; osPost += osGeometryColumnName; osPost += ">\n";
    1670               3 :                 CPLFree(pszGML);
    1671                 :             }
    1672                 :         }
    1673               6 :         if (i == poFeature->GetFieldCount())
    1674               3 :             break;
    1675                 : 
    1676               3 :         if (poFeature->IsFieldSet(i))
    1677                 :         {
    1678               3 :             OGRFieldDefn* poFDefn = poFeature->GetFieldDefnRef(i);
    1679               3 :             osPost += "      <feature:";
    1680               3 :             osPost += poFDefn->GetNameRef();
    1681               3 :             osPost += ">";
    1682               3 :             if (poFDefn->GetType() == OFTInteger)
    1683               0 :                 osPost += CPLSPrintf("%d", poFeature->GetFieldAsInteger(i));
    1684               3 :             else if (poFDefn->GetType() == OFTReal)
    1685               0 :                 osPost += CPLSPrintf("%.16g", poFeature->GetFieldAsDouble(i));
    1686                 :             else
    1687                 :             {
    1688                 :                 char* pszXMLEncoded = CPLEscapeString(poFeature->GetFieldAsString(i),
    1689               3 :                                                 -1, CPLES_XML);
    1690               3 :                 osPost += pszXMLEncoded;
    1691               3 :                 CPLFree(pszXMLEncoded);
    1692                 :             }
    1693               3 :             osPost += "</feature:";
    1694               3 :             osPost += poFDefn->GetNameRef();
    1695               3 :             osPost += ">\n";
    1696                 :         }
    1697                 : 
    1698                 :     }
    1699                 :     
    1700               3 :     osPost += "    </feature:"; osPost += pszShortName; osPost += ">\n";
    1701                 : 
    1702               3 :     if (!bInTransaction)
    1703                 :     {
    1704               1 :         osPost += "  </wfs:Insert>\n";
    1705               1 :         osPost += "</wfs:Transaction>\n";
    1706                 :     }
    1707                 :     else
    1708                 :     {
    1709               2 :         osGlobalInsert += osPost;
    1710               2 :         nExpectedInserts ++;
    1711               2 :         return OGRERR_NONE;
    1712                 :     }
    1713                 : 
    1714               2 :     CPLDebug("WFS", "Post : %s", osPost.c_str());
    1715                 : 
    1716               1 :     char** papszOptions = NULL;
    1717               1 :     papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    1718                 :     papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    1719               1 :                                    "Content-Type: application/xml; charset=UTF-8");
    1720                 : 
    1721               1 :     CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
    1722               1 :     CSLDestroy(papszOptions);
    1723                 : 
    1724               1 :     if (psResult == NULL)
    1725                 :     {
    1726               0 :         return OGRERR_FAILURE;
    1727                 :     }
    1728                 : 
    1729               1 :     if (strstr((const char*)psResult->pabyData,
    1730                 :                                     "<ServiceExceptionReport") != NULL ||
    1731                 :         strstr((const char*)psResult->pabyData,
    1732                 :                                     "<ows:ExceptionReport") != NULL)
    1733                 :     {
    1734                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    1735               0 :                  psResult->pabyData);
    1736               0 :         CPLHTTPDestroyResult(psResult);
    1737               0 :         return OGRERR_FAILURE;
    1738                 :     }
    1739                 : 
    1740               1 :     CPLDebug("WFS", "Response: %s", psResult->pabyData);
    1741                 : 
    1742               1 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    1743               1 :     if (psXML == NULL)
    1744                 :     {
    1745                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    1746               0 :                 psResult->pabyData);
    1747               0 :         CPLHTTPDestroyResult(psResult);
    1748               0 :         return OGRERR_FAILURE;
    1749                 :     }
    1750                 : 
    1751               1 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
    1752               1 :     int bUse100Schema = FALSE;
    1753               1 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
    1754               1 :     if (psRoot == NULL)
    1755                 :     {
    1756               0 :         psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
    1757               0 :         if (psRoot)
    1758               0 :             bUse100Schema = TRUE;
    1759                 :     }
    1760                 : 
    1761               1 :     if (psRoot == NULL)
    1762                 :     {
    1763                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1764               0 :                  "Cannot find <TransactionResponse>");
    1765               0 :         CPLDestroyXMLNode( psXML );
    1766               0 :         CPLHTTPDestroyResult(psResult);
    1767               0 :         return OGRERR_FAILURE;
    1768                 :     }
    1769                 : 
    1770               1 :     CPLXMLNode* psFeatureID = NULL;
    1771                 : 
    1772               1 :     if (bUse100Schema)
    1773                 :     {
    1774               0 :         if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
    1775                 :         {
    1776                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1777                 :                      "Insert failed : %s",
    1778               0 :                      psResult->pabyData);
    1779               0 :             CPLDestroyXMLNode( psXML );
    1780               0 :             CPLHTTPDestroyResult(psResult);
    1781               0 :             return OGRERR_FAILURE;
    1782                 :         }
    1783                 : 
    1784                 :         psFeatureID =
    1785               0 :             CPLGetXMLNode( psRoot, "InsertResult.FeatureId");
    1786               0 :         if (psFeatureID == NULL)
    1787                 :         {
    1788                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1789               0 :                     "Cannot find InsertResult.FeatureId");
    1790               0 :             CPLDestroyXMLNode( psXML );
    1791               0 :             CPLHTTPDestroyResult(psResult);
    1792               0 :             return OGRERR_FAILURE;
    1793                 :         }
    1794                 :     }
    1795                 :     else
    1796                 :     {
    1797                 :         psFeatureID =
    1798               1 :             CPLGetXMLNode( psRoot, "InsertResults.Feature.FeatureId");
    1799               1 :         if (psFeatureID == NULL)
    1800                 :         {
    1801                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1802               0 :                     "Cannot find InsertResults.Feature.FeatureId");
    1803               0 :             CPLDestroyXMLNode( psXML );
    1804               0 :             CPLHTTPDestroyResult(psResult);
    1805               0 :             return OGRERR_FAILURE;
    1806                 :         }
    1807                 :     }
    1808                 : 
    1809               1 :     const char* pszFID = CPLGetXMLValue(psFeatureID, "fid", NULL);
    1810               1 :     if (pszFID == NULL)
    1811                 :     {
    1812               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find fid");
    1813               0 :         CPLDestroyXMLNode( psXML );
    1814               0 :         CPLHTTPDestroyResult(psResult);
    1815               0 :         return OGRERR_FAILURE;
    1816                 :     }
    1817                 : 
    1818               1 :     poFeature->SetField("gml_id", pszFID);
    1819                 : 
    1820                 :     /* If the returned fid is of the form layer_name.num, then use */
    1821                 :     /* num as the OGR FID */
    1822               2 :     if (strncmp(pszFID, pszShortName, strlen(pszShortName)) == 0 &&
    1823               1 :         pszFID[strlen(pszShortName)] == '.')
    1824                 :     {
    1825               1 :         int nFID = atoi(pszFID + strlen(pszShortName) + 1);
    1826                 :         char szTemp[12];
    1827               1 :         sprintf(szTemp, "%d", nFID);
    1828                 :         /* Check that it fits on a int32 */
    1829               1 :         if (strcmp(szTemp, pszFID + strlen(pszShortName) + 1) == 0)
    1830               1 :             poFeature->SetFID(nFID);
    1831                 :     }
    1832                 : 
    1833               1 :     CPLDebug("WFS", "Got FID = %ld", poFeature->GetFID());
    1834                 : 
    1835               1 :     CPLDestroyXMLNode( psXML );
    1836               1 :     CPLHTTPDestroyResult(psResult);
    1837                 : 
    1838                 :     /* Invalidate layer */
    1839               1 :     bReloadNeeded = TRUE;
    1840               1 :     nFeatures = -1;
    1841                 : 
    1842               1 :     return OGRERR_NONE;
    1843                 : }
    1844                 : 
    1845                 : 
    1846                 : /************************************************************************/
    1847                 : /*                             SetFeature()                             */
    1848                 : /************************************************************************/
    1849                 : 
    1850               1 : OGRErr OGRWFSLayer::SetFeature( OGRFeature *poFeature )
    1851                 : {
    1852               1 :     if (!TestCapability(OLCRandomWrite))
    1853                 :     {
    1854               0 :         if (!poDS->SupportTransactions())
    1855                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1856               0 :                      "SetFeature() not supported: no WMS-T features advertized by server");
    1857               0 :         else if (!poDS->UpdateMode())
    1858                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1859               0 :                      "SetFeature() not supported: datasource opened as read-only");
    1860               0 :         return OGRERR_FAILURE;
    1861                 :     }
    1862                 : 
    1863               1 :     if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
    1864                 :     {
    1865                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1866               0 :                  "Cannot find gml_id field");
    1867               0 :         return OGRERR_FAILURE;
    1868                 :     }
    1869                 : 
    1870               1 :     if (poFeature->IsFieldSet(0) == FALSE)
    1871                 :     {
    1872                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1873               0 :                  "Cannot update a feature when gml_id field is not set");
    1874               0 :         return OGRERR_FAILURE;
    1875                 :     }
    1876                 : 
    1877               1 :     if (bInTransaction)
    1878                 :     {
    1879                 :         CPLError(CE_Warning, CPLE_AppDefined,
    1880               0 :                  "SetFeature() not yet dealt in transaction. Issued immediately");
    1881                 :     }
    1882                 : 
    1883               1 :     const char* pszShortName = GetShortName();
    1884                 : 
    1885               1 :     CPLString osPost;
    1886               1 :     osPost += GetPostHeader();
    1887                 : 
    1888               1 :     osPost += "  <wfs:Update typeName=\"feature:"; osPost += pszShortName; osPost +=  "\" xmlns:feature=\"";
    1889               1 :     osPost += osTargetNamespace; osPost += "\">\n";
    1890                 : 
    1891               1 :     CPLLocaleC  oLocaleEnforcer;
    1892                 : 
    1893               1 :     OGRGeometry* poGeom = poFeature->GetGeometryRef();
    1894               1 :     if ( osGeometryColumnName.size() != 0 )
    1895                 :     {
    1896               1 :         osPost += "    <wfs:Property>\n";
    1897               1 :         osPost += "      <wfs:Name>"; osPost += osGeometryColumnName; osPost += "</wfs:Name>\n";
    1898               1 :         if (poGeom != NULL)
    1899                 :         {
    1900               1 :             if (poGeom->getSpatialReference() == NULL)
    1901               0 :                 poGeom->assignSpatialReference(poSRS);
    1902                 :             char* pszGML;
    1903               1 :             if (strcmp(poDS->GetVersion(), "1.1.0") == 0)
    1904                 :             {
    1905               1 :                 char** papszOptions = CSLAddString(NULL, "FORMAT=GML3");
    1906               1 :                 pszGML = OGR_G_ExportToGMLEx((OGRGeometryH)poGeom, papszOptions);
    1907               1 :                 CSLDestroy(papszOptions);
    1908                 :             }
    1909                 :             else
    1910               0 :                 pszGML = OGR_G_ExportToGML((OGRGeometryH)poGeom);
    1911               1 :             osPost += "      <wfs:Value>";
    1912               1 :             osPost += pszGML;
    1913               1 :             osPost += "</wfs:Value>\n";
    1914               1 :             CPLFree(pszGML);
    1915                 :         }
    1916               1 :         osPost += "    </wfs:Property>\n";
    1917                 :     }
    1918                 : 
    1919                 :     int i;
    1920               2 :     for(i=1; i < poFeature->GetFieldCount(); i++)
    1921                 :     {
    1922               1 :         OGRFieldDefn* poFDefn = poFeature->GetFieldDefnRef(i);
    1923                 : 
    1924               1 :         osPost += "    <wfs:Property>\n";
    1925               1 :         osPost += "      <wfs:Name>"; osPost += poFDefn->GetNameRef(); osPost += "</wfs:Name>\n";
    1926               1 :         if (poFeature->IsFieldSet(i))
    1927                 :         {
    1928               1 :             osPost += "      <wfs:Value>";
    1929               1 :             if (poFDefn->GetType() == OFTInteger)
    1930               0 :                 osPost += CPLSPrintf("%d", poFeature->GetFieldAsInteger(i));
    1931               1 :             else if (poFDefn->GetType() == OFTReal)
    1932               0 :                 osPost += CPLSPrintf("%.16g", poFeature->GetFieldAsDouble(i));
    1933                 :             else
    1934                 :             {
    1935                 :                 char* pszXMLEncoded = CPLEscapeString(poFeature->GetFieldAsString(i),
    1936               1 :                                                 -1, CPLES_XML);
    1937               1 :                 osPost += pszXMLEncoded;
    1938               1 :                 CPLFree(pszXMLEncoded);
    1939                 :             }
    1940               1 :             osPost += "</wfs:Value>\n";
    1941                 :         }
    1942               1 :         osPost += "    </wfs:Property>\n";
    1943                 :     }
    1944               1 :     osPost += "    <ogc:Filter>\n";
    1945               1 :     if (poDS->UseFeatureId() || bUseFeatureIdAtLayerLevel)
    1946               0 :         osPost += "      <ogc:FeatureId fid=\"";
    1947               1 :     else if (atoi(poDS->GetVersion()) >= 2)
    1948               0 :         osPost += "      <ogc:ResourceId rid=\"";
    1949                 :     else
    1950               1 :         osPost += "      <ogc:GmlObjectId gml:id=\"";
    1951               1 :     osPost += poFeature->GetFieldAsString(0); osPost += "\"/>\n";
    1952               1 :     osPost += "    </ogc:Filter>\n";
    1953               1 :     osPost += "  </wfs:Update>\n";
    1954               1 :     osPost += "</wfs:Transaction>\n";
    1955                 : 
    1956               1 :     CPLDebug("WFS", "Post : %s", osPost.c_str());
    1957                 : 
    1958               1 :     char** papszOptions = NULL;
    1959               1 :     papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    1960                 :     papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    1961               1 :                                    "Content-Type: application/xml; charset=UTF-8");
    1962                 : 
    1963               1 :     CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
    1964               1 :     CSLDestroy(papszOptions);
    1965                 : 
    1966               1 :     if (psResult == NULL)
    1967                 :     {
    1968               0 :         return OGRERR_FAILURE;
    1969                 :     }
    1970                 : 
    1971               1 :     if (strstr((const char*)psResult->pabyData,
    1972                 :                                     "<ServiceExceptionReport") != NULL ||
    1973                 :         strstr((const char*)psResult->pabyData,
    1974                 :                                     "<ows:ExceptionReport") != NULL)
    1975                 :     {
    1976                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    1977               0 :                  psResult->pabyData);
    1978               0 :         CPLHTTPDestroyResult(psResult);
    1979               0 :         return OGRERR_FAILURE;
    1980                 :     }
    1981                 : 
    1982               1 :     CPLDebug("WFS", "Response: %s", psResult->pabyData);
    1983                 : 
    1984               1 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    1985               1 :     if (psXML == NULL)
    1986                 :     {
    1987                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    1988               0 :                 psResult->pabyData);
    1989               0 :         CPLHTTPDestroyResult(psResult);
    1990               0 :         return OGRERR_FAILURE;
    1991                 :     }
    1992                 : 
    1993               1 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
    1994               1 :     int bUse100Schema = FALSE;
    1995               1 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
    1996               1 :     if (psRoot == NULL)
    1997                 :     {
    1998               0 :         psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
    1999               0 :         if (psRoot)
    2000               0 :             bUse100Schema = TRUE;
    2001                 :     }
    2002               1 :     if (psRoot == NULL)
    2003                 :     {
    2004                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2005               0 :                  "Cannot find <TransactionResponse>");
    2006               0 :         CPLDestroyXMLNode( psXML );
    2007               0 :         CPLHTTPDestroyResult(psResult);
    2008               0 :         return OGRERR_FAILURE;
    2009                 :     }
    2010                 : 
    2011               1 :     if (bUse100Schema)
    2012                 :     {
    2013               0 :         if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
    2014                 :         {
    2015                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2016                 :                      "Update failed : %s",
    2017               0 :                      psResult->pabyData);
    2018               0 :             CPLDestroyXMLNode( psXML );
    2019               0 :             CPLHTTPDestroyResult(psResult);
    2020               0 :             return OGRERR_FAILURE;
    2021                 :         }
    2022                 :     }
    2023                 : 
    2024               1 :     CPLDestroyXMLNode( psXML );
    2025               1 :     CPLHTTPDestroyResult(psResult);
    2026                 : 
    2027                 :     /* Invalidate layer */
    2028               1 :     bReloadNeeded = TRUE;
    2029               1 :     nFeatures = -1;
    2030                 : 
    2031               1 :     return OGRERR_NONE;
    2032                 : }
    2033                 : /************************************************************************/
    2034                 : /*                               GetFeature()                           */
    2035                 : /************************************************************************/
    2036                 : 
    2037               7 : OGRFeature* OGRWFSLayer::GetFeature(long nFID)
    2038                 : {
    2039               7 :     GetLayerDefn();
    2040               7 :     if (poBaseLayer == NULL && poFeatureDefn->GetFieldIndex("gml_id") == 0)
    2041                 :     {
    2042                 :         /* This is lovely hackish. We assume that then gml_id will be */
    2043                 :         /* layer_name.number. This is actually what we can observe with */
    2044                 :         /* GeoServer and TinyOWS */
    2045               2 :         CPLString osVal = CPLSPrintf("gml_id = '%s.%ld'", GetShortName(), nFID);
    2046               2 :         CPLString osOldSQLWhere(osSQLWhere);
    2047               2 :         SetAttributeFilter(osVal);
    2048               2 :         OGRFeature* poFeature = GetNextFeature();
    2049               2 :         const char* pszOldFilter = osOldSQLWhere.size() ? osOldSQLWhere.c_str() : NULL;
    2050               2 :         SetAttributeFilter(pszOldFilter);
    2051               2 :         if (poFeature)
    2052               1 :             return poFeature;
    2053                 :     }
    2054                 : 
    2055               6 :     return OGRLayer::GetFeature(nFID);
    2056                 : }
    2057                 : 
    2058                 : /************************************************************************/
    2059                 : /*                         DeleteFromFilter()                           */
    2060                 : /************************************************************************/
    2061                 : 
    2062               2 : OGRErr OGRWFSLayer::DeleteFromFilter( CPLString osOGCFilter )
    2063                 : {
    2064               2 :     if (!TestCapability(OLCDeleteFeature))
    2065                 :     {
    2066               0 :         if (!poDS->SupportTransactions())
    2067                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2068               0 :                      "DeleteFromFilter() not supported: no WMS-T features advertized by server");
    2069               0 :         else if (!poDS->UpdateMode())
    2070                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2071               0 :                      "DeleteFromFilter() not supported: datasource opened as read-only");
    2072               0 :         return OGRERR_FAILURE;
    2073                 :     }
    2074                 : 
    2075               2 :     if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
    2076                 :     {
    2077                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2078               0 :                  "Cannot find gml_id field");
    2079               0 :         return OGRERR_FAILURE;
    2080                 :     }
    2081               2 :     const char* pszShortName = GetShortName();
    2082                 : 
    2083               2 :     CPLString osPost;
    2084               2 :     osPost += GetPostHeader();
    2085                 : 
    2086               2 :     osPost += "  <wfs:Delete xmlns:feature=\""; osPost += osTargetNamespace;
    2087               2 :     osPost += "\" typeName=\"feature:"; osPost += pszShortName; osPost += "\">\n";
    2088               2 :     osPost += "    <ogc:Filter>\n";
    2089               2 :     osPost += osOGCFilter;
    2090               2 :     osPost += "    </ogc:Filter>\n";
    2091               2 :     osPost += "  </wfs:Delete>\n";
    2092               2 :     osPost += "</wfs:Transaction>\n";
    2093                 : 
    2094               2 :     CPLDebug("WFS", "Post : %s", osPost.c_str());
    2095                 : 
    2096               2 :     char** papszOptions = NULL;
    2097               2 :     papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    2098                 :     papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    2099               2 :                                    "Content-Type: application/xml; charset=UTF-8");
    2100                 : 
    2101               2 :     CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
    2102               2 :     CSLDestroy(papszOptions);
    2103                 : 
    2104               2 :     if (psResult == NULL)
    2105                 :     {
    2106               0 :         return OGRERR_FAILURE;
    2107                 :     }
    2108                 : 
    2109               2 :     if (strstr((const char*)psResult->pabyData, "<ServiceExceptionReport") != NULL ||
    2110                 :         strstr((const char*)psResult->pabyData, "<ows:ExceptionReport") != NULL)
    2111                 :     {
    2112                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    2113               0 :                  psResult->pabyData);
    2114               0 :         CPLHTTPDestroyResult(psResult);
    2115               0 :         return OGRERR_FAILURE;
    2116                 :     }
    2117                 : 
    2118               2 :     CPLDebug("WFS", "Response: %s", psResult->pabyData);
    2119                 : 
    2120               2 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    2121               2 :     if (psXML == NULL)
    2122                 :     {
    2123                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    2124               0 :                 psResult->pabyData);
    2125               0 :         CPLHTTPDestroyResult(psResult);
    2126               0 :         return OGRERR_FAILURE;
    2127                 :     }
    2128                 : 
    2129               2 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
    2130               2 :     int bUse100Schema = FALSE;
    2131               2 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
    2132               2 :     if (psRoot == NULL)
    2133                 :     {
    2134               0 :         psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
    2135               0 :         if (psRoot)
    2136               0 :             bUse100Schema = TRUE;
    2137                 :     }
    2138               2 :     if (psRoot == NULL)
    2139                 :     {
    2140               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <TransactionResponse>");
    2141               0 :         CPLDestroyXMLNode( psXML );
    2142               0 :         CPLHTTPDestroyResult(psResult);
    2143               0 :         return OGRERR_FAILURE;
    2144                 :     }
    2145                 : 
    2146               2 :     if (bUse100Schema)
    2147                 :     {
    2148               0 :         if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
    2149                 :         {
    2150                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2151                 :                      "Delete failed : %s",
    2152               0 :                      psResult->pabyData);
    2153               0 :             CPLDestroyXMLNode( psXML );
    2154               0 :             CPLHTTPDestroyResult(psResult);
    2155               0 :             return OGRERR_FAILURE;
    2156                 :         }
    2157                 :     }
    2158                 : 
    2159               2 :     CPLDestroyXMLNode( psXML );
    2160               2 :     CPLHTTPDestroyResult(psResult);
    2161                 : 
    2162                 :     /* Invalidate layer */
    2163               2 :     bReloadNeeded = TRUE;
    2164               2 :     nFeatures = -1;
    2165                 : 
    2166               2 :     return OGRERR_NONE;
    2167                 : }
    2168                 : 
    2169                 : /************************************************************************/
    2170                 : /*                            DeleteFeature()                           */
    2171                 : /************************************************************************/
    2172                 : 
    2173               1 : OGRErr OGRWFSLayer::DeleteFeature( long nFID )
    2174                 : {
    2175               1 :     if (!TestCapability(OLCDeleteFeature))
    2176                 :     {
    2177               0 :         if (!poDS->SupportTransactions())
    2178                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2179               0 :                      "DeleteFeature() not supported: no WMS-T features advertized by server");
    2180               0 :         else if (!poDS->UpdateMode())
    2181                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2182               0 :                      "DeleteFeature() not supported: datasource opened as read-only");
    2183               0 :         return OGRERR_FAILURE;
    2184                 :     }
    2185                 : 
    2186               1 :     if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
    2187                 :     {
    2188                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2189               0 :                  "Cannot find gml_id field");
    2190               0 :         return OGRERR_FAILURE;
    2191                 :     }
    2192                 : 
    2193               1 :     OGRFeature* poFeature = GetFeature(nFID);
    2194               1 :     if (poFeature == NULL)
    2195                 :     {
    2196                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2197               0 :                  "Cannot find feature %ld", nFID);
    2198               0 :         return OGRERR_FAILURE;
    2199                 :     }
    2200                 : 
    2201               1 :     const char* pszGMLID = poFeature->GetFieldAsString("gml_id");
    2202               1 :     if (pszGMLID == NULL)
    2203                 :     {
    2204                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2205               0 :                  "Cannot delete a feature with gml_id unset");
    2206               0 :         delete poFeature;
    2207               0 :         return OGRERR_FAILURE;
    2208                 :     }
    2209                 : 
    2210               1 :     if (bInTransaction)
    2211                 :     {
    2212                 :         CPLError(CE_Warning, CPLE_AppDefined,
    2213               0 :                  "DeleteFeature() not yet dealt in transaction. Issued immediately");
    2214                 :     }
    2215                 : 
    2216               1 :     CPLString osGMLID = pszGMLID;
    2217               1 :     pszGMLID = NULL;
    2218               1 :     delete poFeature;
    2219               1 :     poFeature = NULL;
    2220                 : 
    2221               1 :     CPLString osFilter;
    2222               1 :     osFilter = "<ogc:FeatureId fid=\""; osFilter += osGMLID; osFilter += "\"/>\n";
    2223               1 :     return DeleteFromFilter(osFilter);
    2224                 : }
    2225                 : 
    2226                 : 
    2227                 : /************************************************************************/
    2228                 : /*                         StartTransaction()                           */
    2229                 : /************************************************************************/
    2230                 : 
    2231               1 : OGRErr OGRWFSLayer::StartTransaction()
    2232                 : {
    2233               1 :     if (!TestCapability(OLCTransactions))
    2234                 :     {
    2235               0 :         if (!poDS->SupportTransactions())
    2236                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2237               0 :                      "StartTransaction() not supported: no WMS-T features advertized by server");
    2238               0 :         else if (!poDS->UpdateMode())
    2239                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2240               0 :                      "StartTransaction() not supported: datasource opened as read-only");
    2241               0 :         return OGRERR_FAILURE;
    2242                 :     }
    2243                 : 
    2244               1 :     if (bInTransaction)
    2245                 :     {
    2246                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2247               0 :                      "StartTransaction() has already been called");
    2248               0 :         return OGRERR_FAILURE;
    2249                 :     }
    2250                 : 
    2251               1 :     bInTransaction = TRUE;
    2252               1 :     osGlobalInsert = "";
    2253               1 :     nExpectedInserts = 0;
    2254               2 :     aosFIDList.resize(0);
    2255                 : 
    2256               1 :     return OGRERR_NONE;
    2257                 : }
    2258                 : 
    2259                 : /************************************************************************/
    2260                 : /*                        CommitTransaction()                           */
    2261                 : /************************************************************************/
    2262                 : 
    2263               1 : OGRErr OGRWFSLayer::CommitTransaction()
    2264                 : {
    2265               1 :     if (!TestCapability(OLCTransactions))
    2266                 :     {
    2267               0 :         if (!poDS->SupportTransactions())
    2268                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2269               0 :                      "CommitTransaction() not supported: no WMS-T features advertized by server");
    2270               0 :         else if (!poDS->UpdateMode())
    2271                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2272               0 :                      "CommitTransaction() not supported: datasource opened as read-only");
    2273               0 :         return OGRERR_FAILURE;
    2274                 :     }
    2275                 : 
    2276               1 :     if (!bInTransaction)
    2277                 :     {
    2278                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2279               0 :                      "StartTransaction() has not yet been called");
    2280               0 :         return OGRERR_FAILURE;
    2281                 :     }
    2282                 : 
    2283               1 :     if (osGlobalInsert.size() != 0)
    2284                 :     {
    2285               1 :         CPLString osPost = GetPostHeader();
    2286               1 :         osPost += "  <wfs:Insert>\n";
    2287               1 :         osPost += osGlobalInsert;
    2288               1 :         osPost += "  </wfs:Insert>\n";
    2289               1 :         osPost += "</wfs:Transaction>\n";
    2290                 : 
    2291               1 :         bInTransaction = FALSE;
    2292               1 :         osGlobalInsert = "";
    2293               1 :         int nExpectedInserts = this->nExpectedInserts;
    2294               1 :         this->nExpectedInserts = 0;
    2295                 : 
    2296               1 :         CPLDebug("WFS", "Post : %s", osPost.c_str());
    2297                 : 
    2298               1 :         char** papszOptions = NULL;
    2299               1 :         papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    2300                 :         papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    2301               1 :                                     "Content-Type: application/xml; charset=UTF-8");
    2302                 : 
    2303               1 :         CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
    2304               1 :         CSLDestroy(papszOptions);
    2305                 : 
    2306               1 :         if (psResult == NULL)
    2307                 :         {
    2308               0 :             return OGRERR_FAILURE;
    2309                 :         }
    2310                 : 
    2311               1 :         if (strstr((const char*)psResult->pabyData,
    2312                 :                                         "<ServiceExceptionReport") != NULL ||
    2313                 :             strstr((const char*)psResult->pabyData,
    2314                 :                                         "<ows:ExceptionReport") != NULL)
    2315                 :         {
    2316                 :             CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    2317               0 :                     psResult->pabyData);
    2318               0 :             CPLHTTPDestroyResult(psResult);
    2319               0 :             return OGRERR_FAILURE;
    2320                 :         }
    2321                 : 
    2322               1 :         CPLDebug("WFS", "Response: %s", psResult->pabyData);
    2323                 : 
    2324               1 :         CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    2325               1 :         if (psXML == NULL)
    2326                 :         {
    2327                 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    2328               0 :                     psResult->pabyData);
    2329               0 :             CPLHTTPDestroyResult(psResult);
    2330               0 :             return OGRERR_FAILURE;
    2331                 :         }
    2332                 : 
    2333               1 :         CPLStripXMLNamespace( psXML, NULL, TRUE );
    2334               1 :         int bUse100Schema = FALSE;
    2335               1 :         CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
    2336               1 :         if (psRoot == NULL)
    2337                 :         {
    2338               0 :             psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
    2339               0 :             if (psRoot)
    2340               0 :                 bUse100Schema = TRUE;
    2341                 :         }
    2342                 : 
    2343               1 :         if (psRoot == NULL)
    2344                 :         {
    2345                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2346               0 :                     "Cannot find <TransactionResponse>");
    2347               0 :             CPLDestroyXMLNode( psXML );
    2348               0 :             CPLHTTPDestroyResult(psResult);
    2349               0 :             return OGRERR_FAILURE;
    2350                 :         }
    2351                 : 
    2352               1 :         if (bUse100Schema)
    2353                 :         {
    2354               0 :             if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
    2355                 :             {
    2356                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2357                 :                         "Insert failed : %s",
    2358               0 :                         psResult->pabyData);
    2359               0 :                 CPLDestroyXMLNode( psXML );
    2360               0 :                 CPLHTTPDestroyResult(psResult);
    2361               0 :                 return OGRERR_FAILURE;
    2362                 :             }
    2363                 : 
    2364                 :             /* TODO */
    2365                 :         }
    2366                 :         else
    2367                 :         {
    2368               1 :             int nGotInserted = atoi(CPLGetXMLValue(psRoot, "TransactionSummary.totalInserted", ""));
    2369               1 :             if (nGotInserted != nExpectedInserts)
    2370                 :             {
    2371                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2372                 :                         "Only %d features were inserted whereas %d where expected",
    2373               0 :                          nGotInserted, nExpectedInserts);
    2374               0 :                 CPLDestroyXMLNode( psXML );
    2375               0 :                 CPLHTTPDestroyResult(psResult);
    2376               0 :                 return OGRERR_FAILURE;
    2377                 :             }
    2378                 : 
    2379                 :             CPLXMLNode* psInsertResults =
    2380               1 :                 CPLGetXMLNode( psRoot, "InsertResults");
    2381               1 :             if (psInsertResults == NULL)
    2382                 :             {
    2383                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2384               0 :                         "Cannot find node InsertResults");
    2385               0 :                 CPLDestroyXMLNode( psXML );
    2386               0 :                 CPLHTTPDestroyResult(psResult);
    2387               0 :                 return OGRERR_FAILURE;
    2388                 :             }
    2389                 : 
    2390               1 :             aosFIDList.resize(0);
    2391                 : 
    2392               1 :             CPLXMLNode* psChild = psInsertResults->psChild;
    2393               4 :             while(psChild)
    2394                 :             {
    2395               2 :                 const char* pszFID = CPLGetXMLValue(psChild, "FeatureId.fid", NULL);
    2396               2 :                 if (pszFID == NULL)
    2397                 :                 {
    2398               0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Cannot find fid");
    2399               0 :                     CPLDestroyXMLNode( psXML );
    2400               0 :                     CPLHTTPDestroyResult(psResult);
    2401               0 :                     return OGRERR_FAILURE;
    2402                 :                 }
    2403               2 :                 aosFIDList.push_back(pszFID);
    2404                 : 
    2405               2 :                 psChild = psChild->psNext;
    2406                 :             }
    2407                 : 
    2408               1 :             if ((int)aosFIDList.size() != nGotInserted)
    2409                 :             {
    2410                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2411               0 :                         "Inconsistant InsertResults: did not get expected FID count");
    2412               0 :                 CPLDestroyXMLNode( psXML );
    2413               0 :                 CPLHTTPDestroyResult(psResult);
    2414               0 :                 return OGRERR_FAILURE;
    2415                 :             }
    2416                 :         }
    2417                 : 
    2418               1 :         CPLDestroyXMLNode( psXML );
    2419               1 :         CPLHTTPDestroyResult(psResult);
    2420                 :     }
    2421                 : 
    2422               1 :     bInTransaction = FALSE;
    2423               1 :     osGlobalInsert = "";
    2424               1 :     nExpectedInserts = 0;
    2425                 : 
    2426               1 :     return OGRERR_NONE;
    2427                 : }
    2428                 : 
    2429                 : /************************************************************************/
    2430                 : /*                      RollbackTransaction()                           */
    2431                 : /************************************************************************/
    2432                 : 
    2433               0 : OGRErr OGRWFSLayer::RollbackTransaction()
    2434                 : {
    2435               0 :     if (!TestCapability(OLCTransactions))
    2436                 :     {
    2437               0 :         if (!poDS->SupportTransactions())
    2438                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2439               0 :                      "RollbackTransaction() not supported: no WMS-T features advertized by server");
    2440               0 :         else if (!poDS->UpdateMode())
    2441                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2442               0 :                      "RollbackTransaction() not supported: datasource opened as read-only");
    2443               0 :         return OGRERR_FAILURE;
    2444                 :     }
    2445                 : 
    2446               0 :     if (!bInTransaction)
    2447                 :     {
    2448                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2449               0 :                      "StartTransaction() has not yet been called");
    2450               0 :         return OGRERR_FAILURE;
    2451                 :     }
    2452                 : 
    2453               0 :     bInTransaction = FALSE;
    2454               0 :     osGlobalInsert = "";
    2455               0 :     nExpectedInserts = 0;
    2456                 : 
    2457               0 :     return OGRERR_NONE;
    2458                 : }
    2459                 : 
    2460                 : /************************************************************************/
    2461                 : /*                    SetRequiredOutputFormat()                         */
    2462                 : /************************************************************************/
    2463                 : 
    2464             154 : void  OGRWFSLayer::SetRequiredOutputFormat(const char* pszRequiredOutputFormatIn)
    2465                 : {
    2466             154 :     CPLFree(pszRequiredOutputFormat);
    2467             154 :     if (pszRequiredOutputFormatIn)
    2468                 :     {
    2469             154 :         pszRequiredOutputFormat = CPLStrdup(pszRequiredOutputFormatIn);
    2470                 :     }
    2471                 :     else
    2472                 :     {
    2473               0 :         pszRequiredOutputFormat = NULL;
    2474                 :     }
    2475             154 : }
    2476                 : 
    2477                 : /************************************************************************/
    2478                 : /*                            SetOrderBy()                              */
    2479                 : /************************************************************************/
    2480                 : 
    2481               1 : void OGRWFSLayer::SetOrderBy(const char* pszFieldToSort, int bAscFlag)
    2482                 : {
    2483               1 :     osFieldToSort = pszFieldToSort ? pszFieldToSort : "";
    2484               1 :     this->bAscFlag = bAscFlag;
    2485               1 : }

Generated by: LCOV version 1.7