LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfslayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1275 631 49.5 %
Date: 2013-03-30 Functions: 40 29 72.5 %

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

Generated by: LCOV version 1.7