LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gml - ogrgmllayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 528 596 88.6 %
Date: 2024-05-06 22:33:47 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OGR
       4             :  * Purpose:  Implements OGRGMLLayer class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
      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 "ogr_gml.h"
      31             : #include "gmlutils.h"
      32             : #include "cpl_conv.h"
      33             : #include "cpl_port.h"
      34             : #include "cpl_string.h"
      35             : #include "ogr_p.h"
      36             : #include "ogr_api.h"
      37             : 
      38             : /************************************************************************/
      39             : /*                           OGRGMLLayer()                              */
      40             : /************************************************************************/
      41             : 
      42         631 : OGRGMLLayer::OGRGMLLayer(const char *pszName, bool bWriterIn,
      43         631 :                          OGRGMLDataSource *poDSIn)
      44             :     : poFeatureDefn(new OGRFeatureDefn(
      45         631 :           pszName + (STARTS_WITH_CI(pszName, "ogr:") ? 4 : 0))),
      46             :       iNextGMLId(0), bInvalidFIDFound(false), pszFIDPrefix(nullptr),
      47             :       bWriter(bWriterIn), bSameSRS(false), poDS(poDSIn),
      48         631 :       poFClass(!bWriter ? poDS->GetReader()->GetClass(pszName) : nullptr),
      49             :       // Reader's should get the corresponding GMLFeatureClass and cache it.
      50        1262 :       hCacheSRS(GML_BuildOGRGeometryFromList_CreateCache()),
      51             :       // Compatibility option. Not advertized, because hopefully won't be
      52             :       // needed. Just put here in case.
      53             :       bUseOldFIDFormat(
      54         631 :           CPLTestBool(CPLGetConfigOption("GML_USE_OLD_FID_FORMAT", "FALSE"))),
      55             :       // Must be in synced in OGR_G_CreateFromGML(), OGRGMLLayer::OGRGMLLayer()
      56             :       // and GMLReader::GMLReader().
      57             :       bFaceHoleNegative(
      58        2524 :           CPLTestBool(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO")))
      59             : {
      60         631 :     SetDescription(poFeatureDefn->GetName());
      61         631 :     poFeatureDefn->Reference();
      62         631 :     poFeatureDefn->SetGeomType(wkbNone);
      63         631 : }
      64             : 
      65             : /************************************************************************/
      66             : /*                           ~OGRGMLLayer()                           */
      67             : /************************************************************************/
      68             : 
      69        1262 : OGRGMLLayer::~OGRGMLLayer()
      70             : 
      71             : {
      72         631 :     CPLFree(pszFIDPrefix);
      73             : 
      74         631 :     if (poFeatureDefn)
      75         631 :         poFeatureDefn->Release();
      76             : 
      77         631 :     GML_BuildOGRGeometryFromList_DestroyCache(hCacheSRS);
      78        1262 : }
      79             : 
      80             : /************************************************************************/
      81             : /*                            ResetReading()                            */
      82             : /************************************************************************/
      83             : 
      84         712 : void OGRGMLLayer::ResetReading()
      85             : 
      86             : {
      87         712 :     if (bWriter)
      88          16 :         return;
      89             : 
      90        1392 :     if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
      91         696 :         poDS->GetReadMode() == SEQUENTIAL_LAYERS)
      92             :     {
      93             :         // Does the last stored feature belong to our layer ? If so, no
      94             :         // need to reset the reader.
      95          88 :         if (iNextGMLId == 0 && poDS->PeekStoredGMLFeature() != nullptr &&
      96           0 :             poDS->PeekStoredGMLFeature()->GetClass() == poFClass)
      97           0 :             return;
      98             : 
      99          88 :         delete poDS->PeekStoredGMLFeature();
     100          88 :         poDS->SetStoredGMLFeature(nullptr);
     101             :     }
     102             : 
     103         696 :     iNextGMLId = 0;
     104         696 :     poDS->GetReader()->ResetReading();
     105         696 :     CPLDebug("GML", "ResetReading()");
     106         696 :     if (poDS->GetLayerCount() > 1 && poDS->GetReadMode() == STANDARD)
     107             :     {
     108          78 :         const char *pszElementName = poFClass->GetElementName();
     109          78 :         const char *pszLastPipe = strrchr(pszElementName, '|');
     110          78 :         if (pszLastPipe != nullptr)
     111          33 :             pszElementName = pszLastPipe + 1;
     112          78 :         poDS->GetReader()->SetFilteredClassName(pszElementName);
     113             :     }
     114             : }
     115             : 
     116             : /************************************************************************/
     117             : /*                              Increment()                             */
     118             : /************************************************************************/
     119             : 
     120         529 : static GIntBig Increment(GIntBig nVal)
     121             : {
     122         529 :     if (nVal <= GINTBIG_MAX - 1)
     123         529 :         return nVal + 1;
     124           0 :     return nVal;
     125             : }
     126             : 
     127             : /************************************************************************/
     128             : /*                           GetNextFeature()                           */
     129             : /************************************************************************/
     130             : 
     131         788 : OGRFeature *OGRGMLLayer::GetNextFeature()
     132             : 
     133             : {
     134         788 :     if (bWriter)
     135             :     {
     136          16 :         CPLError(CE_Failure, CPLE_NotSupported,
     137             :                  "Cannot read features when writing a GML file");
     138          16 :         return nullptr;
     139             :     }
     140             : 
     141         772 :     if (poDS->GetLastReadLayer() != this)
     142             :     {
     143         345 :         if (poDS->GetReadMode() != INTERLEAVED_LAYERS)
     144         336 :             ResetReading();
     145         345 :         poDS->SetLastReadLayer(this);
     146             :     }
     147             : 
     148             :     /* ==================================================================== */
     149             :     /*      Loop till we find and translate a feature meeting all our       */
     150             :     /*      requirements.                                                   */
     151             :     /* ==================================================================== */
     152             :     while (true)
     153             :     {
     154        1427 :         GMLFeature *poGMLFeature = poDS->PeekStoredGMLFeature();
     155        1427 :         if (poGMLFeature != nullptr)
     156             :         {
     157           3 :             poDS->SetStoredGMLFeature(nullptr);
     158             :         }
     159             :         else
     160             :         {
     161        1424 :             poGMLFeature = poDS->GetReader()->NextFeature();
     162        1424 :             if (poGMLFeature == nullptr)
     163         772 :                 return nullptr;
     164             : 
     165             :             // We count reading low level GML features as a feature read for
     166             :             // work checking purposes, though at least we didn't necessary
     167             :             // have to turn it into an OGRFeature.
     168        1297 :             m_nFeaturesRead++;
     169             :         }
     170             : 
     171             :         /* --------------------------------------------------------------------
     172             :          */
     173             :         /*      Is it of the proper feature class? */
     174             :         /* --------------------------------------------------------------------
     175             :          */
     176             : 
     177        1300 :         if (poGMLFeature->GetClass() != poFClass)
     178             :         {
     179        1827 :             if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
     180        1216 :                 (poDS->GetReadMode() == SEQUENTIAL_LAYERS && iNextGMLId != 0))
     181             :             {
     182           4 :                 CPLAssert(poDS->PeekStoredGMLFeature() == nullptr);
     183           4 :                 poDS->SetStoredGMLFeature(poGMLFeature);
     184           4 :                 return nullptr;
     185             :             }
     186             :             else
     187             :             {
     188         607 :                 delete poGMLFeature;
     189         607 :                 continue;
     190             :             }
     191             :         }
     192             : 
     193             :         /* --------------------------------------------------------------------
     194             :          */
     195             :         /*      Extract the fid: */
     196             :         /*      -Assumes the fids are non-negative integers with an optional */
     197             :         /*       prefix */
     198             :         /*      -If a prefix differs from the prefix of the first feature from
     199             :          */
     200             :         /*       the poDS then the fids from the poDS are ignored and are */
     201             :         /*       assigned serially thereafter */
     202             :         /* --------------------------------------------------------------------
     203             :          */
     204         689 :         GIntBig nFID = -1;
     205         689 :         const char *pszGML_FID = poGMLFeature->GetFID();
     206         689 :         if (bInvalidFIDFound)
     207             :         {
     208          43 :             nFID = iNextGMLId;
     209          43 :             iNextGMLId = Increment(iNextGMLId);
     210             :         }
     211         646 :         else if (pszGML_FID == nullptr)
     212             :         {
     213         108 :             bInvalidFIDFound = true;
     214         108 :             nFID = iNextGMLId;
     215         108 :             iNextGMLId = Increment(iNextGMLId);
     216             :         }
     217         538 :         else if (iNextGMLId == 0)
     218             :         {
     219         261 :             int j = 0;
     220         261 :             int i = static_cast<int>(strlen(pszGML_FID)) - 1;
     221         645 :             while (i >= 0 && pszGML_FID[i] >= '0' && pszGML_FID[i] <= '9' &&
     222             :                    j < 20)
     223             :             {
     224         384 :                 i--;
     225         384 :                 j++;
     226             :             }
     227             :             // i points the last character of the fid.
     228         261 :             if (i >= 0 && j < 20 && pszFIDPrefix == nullptr)
     229             :             {
     230         198 :                 pszFIDPrefix = static_cast<char *>(CPLMalloc(i + 2));
     231         198 :                 pszFIDPrefix[i + 1] = '\0';
     232         198 :                 strncpy(pszFIDPrefix, pszGML_FID, i + 1);
     233             :             }
     234             :             // pszFIDPrefix now contains the prefix or NULL if no prefix is
     235             :             // found.
     236         261 :             if (j < 20 && sscanf(pszGML_FID + i + 1, CPL_FRMT_GIB, &nFID) == 1)
     237             :             {
     238         255 :                 if (iNextGMLId <= nFID)
     239         255 :                     iNextGMLId = Increment(nFID);
     240             :             }
     241             :             else
     242             :             {
     243           6 :                 bInvalidFIDFound = true;
     244           6 :                 nFID = iNextGMLId;
     245           6 :                 iNextGMLId = Increment(iNextGMLId);
     246             :             }
     247             :         }
     248             :         else  // if( iNextGMLId != 0 ).
     249             :         {
     250         277 :             const char *pszFIDPrefix_notnull = pszFIDPrefix;
     251         277 :             if (pszFIDPrefix_notnull == nullptr)
     252           6 :                 pszFIDPrefix_notnull = "";
     253         277 :             int nLenPrefix = static_cast<int>(strlen(pszFIDPrefix_notnull));
     254             : 
     255         827 :             if (strncmp(pszGML_FID, pszFIDPrefix_notnull, nLenPrefix) == 0 &&
     256         550 :                 strlen(pszGML_FID + nLenPrefix) < 20 &&
     257         273 :                 sscanf(pszGML_FID + nLenPrefix, CPL_FRMT_GIB, &nFID) == 1)
     258             :             {
     259             :                 // fid with the prefix. Using its numerical part.
     260         272 :                 if (iNextGMLId < nFID)
     261         112 :                     iNextGMLId = Increment(nFID);
     262             :             }
     263             :             else
     264             :             {
     265             :                 // fid without the aforementioned prefix or a valid numerical
     266             :                 // part.
     267           5 :                 bInvalidFIDFound = true;
     268           5 :                 nFID = iNextGMLId;
     269           5 :                 iNextGMLId = Increment(iNextGMLId);
     270             :             }
     271             :         }
     272             : 
     273             :         /* --------------------------------------------------------------------
     274             :          */
     275             :         /*      Does it satisfy the spatial query, if there is one? */
     276             :         /* --------------------------------------------------------------------
     277             :          */
     278             : 
     279         689 :         OGRGeometry **papoGeometries = nullptr;
     280         689 :         const CPLXMLNode *const *papsGeometry = poGMLFeature->GetGeometryList();
     281             : 
     282         689 :         const CPLXMLNode *apsGeometries[2] = {nullptr, nullptr};
     283             :         const CPLXMLNode *psBoundedByGeometry =
     284         689 :             poGMLFeature->GetBoundedByGeometry();
     285         689 :         if (psBoundedByGeometry && !(papsGeometry && papsGeometry[0]))
     286             :         {
     287           6 :             apsGeometries[0] = psBoundedByGeometry;
     288           6 :             papsGeometry = apsGeometries;
     289             :         }
     290             : 
     291         689 :         OGRGeometry *poGeom = nullptr;
     292             : 
     293         689 :         if (poFeatureDefn->GetGeomFieldCount() > 1)
     294             :         {
     295         188 :             papoGeometries = static_cast<OGRGeometry **>(CPLCalloc(
     296          94 :                 poFeatureDefn->GetGeomFieldCount(), sizeof(OGRGeometry *)));
     297          94 :             const char *pszSRSName = poDS->GetGlobalSRSName();
     298         301 :             for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
     299             :             {
     300         207 :                 const CPLXMLNode *psGeom = poGMLFeature->GetGeometryRef(i);
     301         207 :                 if (psGeom != nullptr)
     302             :                 {
     303         163 :                     const CPLXMLNode *myGeometryList[2] = {psGeom, nullptr};
     304         163 :                     poGeom = GML_BuildOGRGeometryFromList(
     305             :                         myGeometryList, true,
     306         163 :                         poDS->GetInvertAxisOrderIfLatLong(), pszSRSName,
     307         163 :                         poDS->GetConsiderEPSGAsURN(),
     308         163 :                         poDS->GetSwapCoordinates(),
     309         163 :                         poDS->GetSecondaryGeometryOption(), hCacheSRS,
     310         163 :                         bFaceHoleNegative);
     311             : 
     312             :                     // Do geometry type changes if needed to match layer
     313             :                     // geometry type.
     314         163 :                     if (poGeom != nullptr)
     315             :                     {
     316         163 :                         papoGeometries[i] = OGRGeometryFactory::forceTo(
     317             :                             poGeom,
     318         163 :                             poFeatureDefn->GetGeomFieldDefn(i)->GetType());
     319         163 :                         poGeom = nullptr;
     320             :                     }
     321             :                     else
     322             :                     {
     323             :                         // We assume the createFromGML() function would have
     324             :                         // already reported the error.
     325           0 :                         for (int j = 0; j < poFeatureDefn->GetGeomFieldCount();
     326             :                              j++)
     327             :                         {
     328           0 :                             delete papoGeometries[j];
     329             :                         }
     330           0 :                         CPLFree(papoGeometries);
     331           0 :                         delete poGMLFeature;
     332           0 :                         return nullptr;
     333             :                     }
     334             :                 }
     335             :             }
     336             : 
     337           0 :             if (m_poFilterGeom != nullptr && m_iGeomFieldFilter >= 0 &&
     338           0 :                 m_iGeomFieldFilter < poFeatureDefn->GetGeomFieldCount() &&
     339          94 :                 papoGeometries[m_iGeomFieldFilter] &&
     340           0 :                 !FilterGeometry(papoGeometries[m_iGeomFieldFilter]))
     341             :             {
     342           0 :                 for (int j = 0; j < poFeatureDefn->GetGeomFieldCount(); j++)
     343             :                 {
     344           0 :                     delete papoGeometries[j];
     345             :                 }
     346           0 :                 CPLFree(papoGeometries);
     347           0 :                 delete poGMLFeature;
     348           0 :                 continue;
     349             :             }
     350             :         }
     351         595 :         else if (papsGeometry[0] &&
     352         497 :                  strcmp(papsGeometry[0]->pszValue, "null") == 0)
     353             :         {
     354             :             // do nothing
     355             :         }
     356         591 :         else if (papsGeometry[0] != nullptr)
     357             :         {
     358         493 :             const char *pszSRSName = poDS->GetGlobalSRSName();
     359         493 :             CPLPushErrorHandler(CPLQuietErrorHandler);
     360         493 :             poGeom = GML_BuildOGRGeometryFromList(
     361         493 :                 papsGeometry, true, poDS->GetInvertAxisOrderIfLatLong(),
     362         493 :                 pszSRSName, poDS->GetConsiderEPSGAsURN(),
     363         493 :                 poDS->GetSwapCoordinates(), poDS->GetSecondaryGeometryOption(),
     364         493 :                 hCacheSRS, bFaceHoleNegative);
     365         493 :             CPLPopErrorHandler();
     366             : 
     367             :             // Do geometry type changes if needed to match layer geometry type.
     368         493 :             if (poGeom != nullptr)
     369             :             {
     370         493 :                 poGeom = OGRGeometryFactory::forceTo(poGeom, GetGeomType());
     371             :             }
     372             :             else
     373             :             {
     374           0 :                 const CPLString osLastErrorMsg(CPLGetLastErrorMsg());
     375             : 
     376           0 :                 const bool bGoOn = CPLTestBool(
     377             :                     CPLGetConfigOption("GML_SKIP_CORRUPTED_FEATURES", "NO"));
     378             : 
     379           0 :                 CPLError(
     380             :                     bGoOn ? CE_Warning : CE_Failure, CPLE_AppDefined,
     381             :                     "Geometry of feature " CPL_FRMT_GIB
     382             :                     " %scannot be parsed: %s%s",
     383           0 :                     nFID, pszGML_FID ? CPLSPrintf("%s ", pszGML_FID) : "",
     384             :                     osLastErrorMsg.c_str(),
     385             :                     bGoOn ? ". Skipping to next feature."
     386             :                           : ". You may set the GML_SKIP_CORRUPTED_FEATURES "
     387             :                             "configuration option to YES to skip to the next "
     388             :                             "feature");
     389           0 :                 delete poGMLFeature;
     390           0 :                 if (bGoOn)
     391           0 :                     continue;
     392           0 :                 return nullptr;
     393             :             }
     394             : 
     395         493 :             if (m_poFilterGeom != nullptr && !FilterGeometry(poGeom))
     396             :             {
     397          20 :                 delete poGMLFeature;
     398          20 :                 delete poGeom;
     399          20 :                 continue;
     400             :             }
     401             :         }
     402             : 
     403             :         /* --------------------------------------------------------------------
     404             :          */
     405             :         /*      Convert the whole feature into an OGRFeature. */
     406             :         /* --------------------------------------------------------------------
     407             :          */
     408         669 :         int iDstField = 0;
     409         669 :         OGRFeature *poOGRFeature = new OGRFeature(poFeatureDefn);
     410             : 
     411         669 :         poOGRFeature->SetFID(nFID);
     412         669 :         if (poDS->ExposeId())
     413             :         {
     414         561 :             if (pszGML_FID)
     415         525 :                 poOGRFeature->SetField(iDstField, pszGML_FID);
     416         561 :             iDstField++;
     417             :         }
     418             : 
     419         669 :         const int nPropertyCount = poFClass->GetPropertyCount();
     420        3204 :         for (int iField = 0; iField < nPropertyCount; iField++, iDstField++)
     421             :         {
     422             :             const GMLProperty *psGMLProperty =
     423        2535 :                 poGMLFeature->GetProperty(iField);
     424        2535 :             if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
     425         557 :                 continue;
     426             : 
     427        1978 :             if (EQUAL(psGMLProperty->papszSubProperties[0], OGR_GML_NULL))
     428             :             {
     429           1 :                 poOGRFeature->SetFieldNull(iDstField);
     430           1 :                 continue;
     431             :             }
     432             : 
     433        1977 :             switch (poFClass->GetProperty(iField)->GetType())
     434             :             {
     435         325 :                 case GMLPT_Real:
     436             :                 {
     437         325 :                     poOGRFeature->SetField(
     438             :                         iDstField,
     439         325 :                         CPLAtof(psGMLProperty->papszSubProperties[0]));
     440             :                 }
     441         325 :                 break;
     442             : 
     443          13 :                 case GMLPT_IntegerList:
     444             :                 {
     445          13 :                     const int nCount = psGMLProperty->nSubProperties;
     446             :                     int *panIntList =
     447          13 :                         static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
     448             : 
     449          39 :                     for (int i = 0; i < nCount; i++)
     450          26 :                         panIntList[i] =
     451          26 :                             atoi(psGMLProperty->papszSubProperties[i]);
     452             : 
     453          13 :                     poOGRFeature->SetField(iDstField, nCount, panIntList);
     454          13 :                     CPLFree(panIntList);
     455             :                 }
     456          13 :                 break;
     457             : 
     458           6 :                 case GMLPT_Integer64List:
     459             :                 {
     460           6 :                     const int nCount = psGMLProperty->nSubProperties;
     461             :                     GIntBig *panIntList = static_cast<GIntBig *>(
     462           6 :                         CPLMalloc(sizeof(GIntBig) * nCount));
     463             : 
     464          15 :                     for (int i = 0; i < nCount; i++)
     465          18 :                         panIntList[i] =
     466           9 :                             CPLAtoGIntBig(psGMLProperty->papszSubProperties[i]);
     467             : 
     468           6 :                     poOGRFeature->SetField(iDstField, nCount, panIntList);
     469           6 :                     CPLFree(panIntList);
     470             :                 }
     471           6 :                 break;
     472             : 
     473          25 :                 case GMLPT_RealList:
     474             :                 {
     475          25 :                     const int nCount = psGMLProperty->nSubProperties;
     476             :                     double *padfList = static_cast<double *>(
     477          25 :                         CPLMalloc(sizeof(double) * nCount));
     478             : 
     479          59 :                     for (int i = 0; i < nCount; i++)
     480          68 :                         padfList[i] =
     481          34 :                             CPLAtof(psGMLProperty->papszSubProperties[i]);
     482             : 
     483          25 :                     poOGRFeature->SetField(iDstField, nCount, padfList);
     484          25 :                     CPLFree(padfList);
     485             :                 }
     486          25 :                 break;
     487             : 
     488         106 :                 case GMLPT_StringList:
     489             :                 case GMLPT_FeaturePropertyList:
     490             :                 {
     491         106 :                     poOGRFeature->SetField(iDstField,
     492         106 :                                            psGMLProperty->papszSubProperties);
     493             :                 }
     494         106 :                 break;
     495             : 
     496          46 :                 case GMLPT_Boolean:
     497             :                 {
     498          46 :                     if (strcmp(psGMLProperty->papszSubProperties[0], "true") ==
     499           7 :                             0 ||
     500           7 :                         strcmp(psGMLProperty->papszSubProperties[0], "1") == 0)
     501             :                     {
     502          39 :                         poOGRFeature->SetField(iDstField, 1);
     503             :                     }
     504           7 :                     else if (strcmp(psGMLProperty->papszSubProperties[0],
     505           0 :                                     "false") == 0 ||
     506           0 :                              strcmp(psGMLProperty->papszSubProperties[0],
     507             :                                     "0") == 0)
     508             :                     {
     509           7 :                         poOGRFeature->SetField(iDstField, 0);
     510             :                     }
     511             :                     else
     512             :                     {
     513           0 :                         poOGRFeature->SetField(
     514           0 :                             iDstField, psGMLProperty->papszSubProperties[0]);
     515             :                     }
     516          46 :                     break;
     517             :                 }
     518             : 
     519           3 :                 case GMLPT_BooleanList:
     520             :                 {
     521           3 :                     const int nCount = psGMLProperty->nSubProperties;
     522             :                     int *panIntList =
     523           3 :                         static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
     524             : 
     525           9 :                     for (int i = 0; i < nCount; i++)
     526             :                     {
     527           6 :                         panIntList[i] =
     528           6 :                             (strcmp(psGMLProperty->papszSubProperties[i],
     529           9 :                                     "true") == 0 ||
     530           3 :                              strcmp(psGMLProperty->papszSubProperties[i],
     531             :                                     "1") == 0);
     532             :                     }
     533             : 
     534           3 :                     poOGRFeature->SetField(iDstField, nCount, panIntList);
     535           3 :                     CPLFree(panIntList);
     536           3 :                     break;
     537             :                 }
     538             : 
     539        1453 :                 default:
     540        1453 :                     poOGRFeature->SetField(
     541        1453 :                         iDstField, psGMLProperty->papszSubProperties[0]);
     542        1453 :                     break;
     543             :             }
     544             :         }
     545             : 
     546         669 :         delete poGMLFeature;
     547         669 :         poGMLFeature = nullptr;
     548             : 
     549             :         // Assign the geometry before the attribute filter because
     550             :         // the attribute filter may use a special field like OGR_GEOMETRY.
     551         669 :         if (papoGeometries != nullptr)
     552             :         {
     553         301 :             for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
     554             :             {
     555         207 :                 poOGRFeature->SetGeomFieldDirectly(i, papoGeometries[i]);
     556             :             }
     557          94 :             CPLFree(papoGeometries);
     558          94 :             papoGeometries = nullptr;
     559             :         }
     560             :         else
     561             :         {
     562         575 :             poOGRFeature->SetGeometryDirectly(poGeom);
     563             :         }
     564             : 
     565             :         // Assign SRS.
     566        1392 :         for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
     567             :         {
     568         723 :             poGeom = poOGRFeature->GetGeomFieldRef(i);
     569         723 :             if (poGeom != nullptr)
     570             :             {
     571             :                 const OGRSpatialReference *poSRS =
     572         636 :                     poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef();
     573         636 :                 if (poSRS != nullptr)
     574         132 :                     poGeom->assignSpatialReference(poSRS);
     575             :             }
     576             :         }
     577             : 
     578             :         /* --------------------------------------------------------------------
     579             :          */
     580             :         /*      Test against the attribute query. */
     581             :         /* --------------------------------------------------------------------
     582             :          */
     583         669 :         if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
     584             :         {
     585          28 :             delete poOGRFeature;
     586          28 :             continue;
     587             :         }
     588             : 
     589             :         // Got the desired feature.
     590         641 :         return poOGRFeature;
     591         655 :     }
     592             : 
     593             :     return nullptr;
     594             : }
     595             : 
     596             : /************************************************************************/
     597             : /*                          GetFeatureCount()                           */
     598             : /************************************************************************/
     599             : 
     600          62 : GIntBig OGRGMLLayer::GetFeatureCount(int bForce)
     601             : 
     602             : {
     603          62 :     if (poFClass == nullptr)
     604           0 :         return 0;
     605             : 
     606          62 :     if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
     607           6 :         return OGRLayer::GetFeatureCount(bForce);
     608             : 
     609             :     // If the schema is read from a .xsd file, we haven't read
     610             :     // the feature count, so compute it now.
     611          56 :     GIntBig nFeatureCount = poFClass->GetFeatureCount();
     612          56 :     if (nFeatureCount < 0)
     613             :     {
     614          26 :         nFeatureCount = OGRLayer::GetFeatureCount(bForce);
     615          26 :         poFClass->SetFeatureCount(nFeatureCount);
     616             :     }
     617             : 
     618          56 :     return nFeatureCount;
     619             : }
     620             : 
     621             : /************************************************************************/
     622             : /*                             GetExtent()                              */
     623             : /************************************************************************/
     624             : 
     625          10 : OGRErr OGRGMLLayer::GetExtent(OGREnvelope *psExtent, int bForce)
     626             : 
     627             : {
     628          10 :     if (GetGeomType() == wkbNone)
     629           0 :         return OGRERR_FAILURE;
     630             : 
     631          10 :     double dfXMin = 0.0;
     632          10 :     double dfXMax = 0.0;
     633          10 :     double dfYMin = 0.0;
     634          10 :     double dfYMax = 0.0;
     635          20 :     if (poFClass != nullptr &&
     636          10 :         poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax))
     637             :     {
     638           8 :         psExtent->MinX = dfXMin;
     639           8 :         psExtent->MaxX = dfXMax;
     640           8 :         psExtent->MinY = dfYMin;
     641           8 :         psExtent->MaxY = dfYMax;
     642             : 
     643           8 :         return OGRERR_NONE;
     644             :     }
     645             : 
     646           2 :     return OGRLayer::GetExtent(psExtent, bForce);
     647             : }
     648             : 
     649             : /************************************************************************/
     650             : /*                             GetExtent()                              */
     651             : /************************************************************************/
     652             : 
     653         505 : static void GMLWriteField(OGRGMLDataSource *poDS, VSILFILE *fp,
     654             :                           bool bWriteSpaceIndentation, const char *pszPrefix,
     655             :                           bool bRemoveAppPrefix, OGRFieldDefn *poFieldDefn,
     656             :                           const char *pszVal)
     657             : 
     658             : {
     659         505 :     const char *pszFieldName = poFieldDefn->GetNameRef();
     660             : 
     661         505 :     while (*pszVal == ' ')
     662           0 :         pszVal++;
     663             : 
     664         505 :     if (bWriteSpaceIndentation)
     665         505 :         VSIFPrintfL(fp, "      ");
     666             : 
     667         505 :     if (bRemoveAppPrefix)
     668          60 :         poDS->PrintLine(fp, "<%s>%s</%s>", pszFieldName, pszVal, pszFieldName);
     669             :     else
     670         445 :         poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix, pszFieldName,
     671             :                         pszVal, pszPrefix, pszFieldName);
     672         505 : }
     673             : 
     674             : /************************************************************************/
     675             : /*                           ICreateFeature()                            */
     676             : /************************************************************************/
     677             : 
     678         253 : OGRErr OGRGMLLayer::ICreateFeature(OGRFeature *poFeature)
     679             : 
     680             : {
     681         253 :     const bool bIsGML3Output = poDS->IsGML3Output();
     682         253 :     VSILFILE *fp = poDS->GetOutputFP();
     683         253 :     const bool bWriteSpaceIndentation = poDS->WriteSpaceIndentation();
     684         253 :     const char *pszPrefix = poDS->GetAppPrefix();
     685         253 :     const bool bRemoveAppPrefix = poDS->RemoveAppPrefix();
     686         253 :     const bool bGMLFeatureCollection = poDS->GMLFeatureCollection();
     687             : 
     688         253 :     if (!bWriter)
     689           0 :         return OGRERR_FAILURE;
     690             : 
     691         253 :     poFeature->FillUnsetWithDefault(TRUE, nullptr);
     692         253 :     if (!poFeature->Validate(OGR_F_VAL_ALL & ~OGR_F_VAL_GEOM_TYPE &
     693             :                                  ~OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT,
     694             :                              TRUE))
     695           2 :         return OGRERR_FAILURE;
     696             : 
     697         251 :     if (bWriteSpaceIndentation)
     698         251 :         VSIFPrintfL(fp, "  ");
     699         251 :     if (bIsGML3Output && !bGMLFeatureCollection)
     700             :     {
     701         207 :         if (bRemoveAppPrefix)
     702          10 :             poDS->PrintLine(fp, "<featureMember>");
     703             :         else
     704         197 :             poDS->PrintLine(fp, "<%s:featureMember>", pszPrefix);
     705             :     }
     706             :     else
     707             :     {
     708          44 :         poDS->PrintLine(fp, "<gml:featureMember>");
     709             :     }
     710             : 
     711         251 :     if (iNextGMLId == 0)
     712             :     {
     713         109 :         bSameSRS = true;
     714         114 :         for (int iGeomField = 1;
     715         114 :              iGeomField < poFeatureDefn->GetGeomFieldCount(); iGeomField++)
     716             :         {
     717           5 :             OGRGeomFieldDefn *poFieldDefn0 = poFeatureDefn->GetGeomFieldDefn(0);
     718             :             OGRGeomFieldDefn *poFieldDefn =
     719           5 :                 poFeatureDefn->GetGeomFieldDefn(iGeomField);
     720           5 :             const OGRSpatialReference *poSRS0 = poFieldDefn0->GetSpatialRef();
     721           5 :             const OGRSpatialReference *poSRS = poFieldDefn->GetSpatialRef();
     722           5 :             if (poSRS0 != nullptr && poSRS == nullptr)
     723             :             {
     724           0 :                 bSameSRS = false;
     725             :             }
     726           5 :             else if (poSRS0 == nullptr && poSRS != nullptr)
     727             :             {
     728           0 :                 bSameSRS = false;
     729             :             }
     730           7 :             else if (poSRS0 != nullptr && poSRS != nullptr && poSRS0 != poSRS &&
     731           2 :                      !poSRS0->IsSame(poSRS))
     732             :             {
     733           1 :                 bSameSRS = false;
     734             :             }
     735             :         }
     736             :     }
     737             : 
     738         251 :     if (poFeature->GetFID() == OGRNullFID)
     739         238 :         poFeature->SetFID(iNextGMLId++);
     740             : 
     741         251 :     if (bWriteSpaceIndentation)
     742         251 :         VSIFPrintfL(fp, "    ");
     743         251 :     VSIFPrintfL(fp, "<");
     744         251 :     if (!bRemoveAppPrefix)
     745         231 :         VSIFPrintfL(fp, "%s:", pszPrefix);
     746             : 
     747         251 :     int nGMLIdIndex = -1;
     748         251 :     if (bIsGML3Output)
     749             :     {
     750         217 :         nGMLIdIndex = poFeatureDefn->GetFieldIndex("gml_id");
     751         217 :         if (nGMLIdIndex >= 0 && poFeature->IsFieldSetAndNotNull(nGMLIdIndex))
     752           3 :             poDS->PrintLine(fp, "%s gml:id=\"%s\">", poFeatureDefn->GetName(),
     753             :                             poFeature->GetFieldAsString(nGMLIdIndex));
     754             :         else
     755         428 :             poDS->PrintLine(fp, "%s gml:id=\"%s." CPL_FRMT_GIB "\">",
     756         214 :                             poFeatureDefn->GetName(), poFeatureDefn->GetName(),
     757             :                             poFeature->GetFID());
     758             :     }
     759             :     else
     760             :     {
     761          34 :         nGMLIdIndex = poFeatureDefn->GetFieldIndex("fid");
     762          34 :         if (bUseOldFIDFormat)
     763             :         {
     764           0 :             poDS->PrintLine(fp, "%s fid=\"F" CPL_FRMT_GIB "\">",
     765           0 :                             poFeatureDefn->GetName(), poFeature->GetFID());
     766             :         }
     767          44 :         else if (nGMLIdIndex >= 0 &&
     768          10 :                  poFeature->IsFieldSetAndNotNull(nGMLIdIndex))
     769             :         {
     770          10 :             poDS->PrintLine(fp, "%s fid=\"%s\">", poFeatureDefn->GetName(),
     771             :                             poFeature->GetFieldAsString(nGMLIdIndex));
     772             :         }
     773             :         else
     774             :         {
     775          48 :             poDS->PrintLine(fp, "%s fid=\"%s." CPL_FRMT_GIB "\">",
     776          24 :                             poFeatureDefn->GetName(), poFeatureDefn->GetName(),
     777             :                             poFeature->GetFID());
     778             :         }
     779             :     }
     780             : 
     781         491 :     for (int iGeomField = 0; iGeomField < poFeatureDefn->GetGeomFieldCount();
     782             :          iGeomField++)
     783             :     {
     784             :         const OGRGeomFieldDefn *poFieldDefn =
     785         240 :             poFeatureDefn->GetGeomFieldDefn(iGeomField);
     786             : 
     787             :         // Write out Geometry - for now it isn't indented properly.
     788             :         // GML geometries don't like very much the concept of empty geometry.
     789         240 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
     790         240 :         if (poGeom != nullptr && !poGeom->IsEmpty())
     791             :         {
     792         203 :             OGREnvelope3D sGeomBounds;
     793             : 
     794         203 :             const int nCoordDimension = poGeom->getCoordinateDimension();
     795             : 
     796         203 :             poGeom->getEnvelope(&sGeomBounds);
     797         203 :             if (bSameSRS)
     798         201 :                 poDS->GrowExtents(&sGeomBounds, nCoordDimension);
     799             : 
     800         338 :             if (poGeom->getSpatialReference() == nullptr &&
     801         135 :                 poFieldDefn->GetSpatialRef() != nullptr)
     802          18 :                 poGeom->assignSpatialReference(poFieldDefn->GetSpatialRef());
     803             : 
     804         203 :             const auto &oCoordPrec = poFieldDefn->GetCoordinatePrecision();
     805             : 
     806         203 :             if (bIsGML3Output && poDS->WriteFeatureBoundedBy())
     807             :             {
     808         159 :                 bool bCoordSwap = false;
     809             : 
     810             :                 char *pszSRSName =
     811         159 :                     GML_GetSRSName(poGeom->getSpatialReference(),
     812         159 :                                    poDS->GetSRSNameFormat(), &bCoordSwap);
     813         159 :                 char szLowerCorner[75] = {};
     814         159 :                 char szUpperCorner[75] = {};
     815             : 
     816         159 :                 OGRWktOptions coordOpts;
     817             : 
     818         159 :                 if (oCoordPrec.dfXYResolution !=
     819             :                     OGRGeomCoordinatePrecision::UNKNOWN)
     820             :                 {
     821           3 :                     coordOpts.format = OGRWktFormat::F;
     822           3 :                     coordOpts.xyPrecision =
     823           3 :                         OGRGeomCoordinatePrecision::ResolutionToPrecision(
     824           3 :                             oCoordPrec.dfXYResolution);
     825             :                 }
     826         159 :                 if (oCoordPrec.dfZResolution !=
     827             :                     OGRGeomCoordinatePrecision::UNKNOWN)
     828             :                 {
     829           3 :                     coordOpts.format = OGRWktFormat::F;
     830           3 :                     coordOpts.zPrecision =
     831           3 :                         OGRGeomCoordinatePrecision::ResolutionToPrecision(
     832           3 :                             oCoordPrec.dfZResolution);
     833             :                 }
     834             : 
     835         318 :                 std::string wkt;
     836         159 :                 if (bCoordSwap)
     837             :                 {
     838          24 :                     wkt = OGRMakeWktCoordinate(
     839             :                         sGeomBounds.MinY, sGeomBounds.MinX, sGeomBounds.MinZ,
     840          12 :                         nCoordDimension, coordOpts);
     841          12 :                     memcpy(szLowerCorner, wkt.data(), wkt.size() + 1);
     842             : 
     843          24 :                     wkt = OGRMakeWktCoordinate(
     844             :                         sGeomBounds.MaxY, sGeomBounds.MaxX, sGeomBounds.MaxZ,
     845          12 :                         nCoordDimension, coordOpts);
     846          12 :                     memcpy(szUpperCorner, wkt.data(), wkt.size() + 1);
     847             :                 }
     848             :                 else
     849             :                 {
     850         294 :                     wkt = OGRMakeWktCoordinate(
     851             :                         sGeomBounds.MinX, sGeomBounds.MinY, sGeomBounds.MinZ,
     852         147 :                         nCoordDimension, coordOpts);
     853         147 :                     memcpy(szLowerCorner, wkt.data(), wkt.size() + 1);
     854             : 
     855         294 :                     wkt = OGRMakeWktCoordinate(
     856             :                         sGeomBounds.MaxX, sGeomBounds.MaxY, sGeomBounds.MaxZ,
     857         147 :                         nCoordDimension, coordOpts);
     858         147 :                     memcpy(szUpperCorner, wkt.data(), wkt.size() + 1);
     859             :                 }
     860         159 :                 if (bWriteSpaceIndentation)
     861         159 :                     VSIFPrintfL(fp, "      ");
     862         159 :                 poDS->PrintLine(
     863             :                     fp,
     864             :                     "<gml:boundedBy><gml:Envelope%s%s><gml:lowerCorner>%s"
     865             :                     "</gml:lowerCorner><gml:upperCorner>%s</gml:upperCorner>"
     866             :                     "</gml:Envelope></gml:boundedBy>",
     867             :                     (nCoordDimension == 3) ? " srsDimension=\"3\"" : "",
     868             :                     pszSRSName, szLowerCorner, szUpperCorner);
     869         159 :                 CPLFree(pszSRSName);
     870             :             }
     871             : 
     872         203 :             char **papszOptions = nullptr;
     873         203 :             if (bIsGML3Output)
     874             :             {
     875         169 :                 papszOptions = CSLAddString(papszOptions, "FORMAT=GML3");
     876         169 :                 if (poDS->GetSRSNameFormat() == SRSNAME_SHORT)
     877             :                     papszOptions =
     878           1 :                         CSLAddString(papszOptions, "SRSNAME_FORMAT=SHORT");
     879         168 :                 else if (poDS->GetSRSNameFormat() == SRSNAME_OGC_URN)
     880             :                     papszOptions =
     881         155 :                         CSLAddString(papszOptions, "SRSNAME_FORMAT=OGC_URN");
     882          13 :                 else if (poDS->GetSRSNameFormat() == SRSNAME_OGC_URL)
     883             :                     papszOptions =
     884          13 :                         CSLAddString(papszOptions, "SRSNAME_FORMAT=OGC_URL");
     885             :             }
     886         203 :             const char *pszSRSDimensionLoc = poDS->GetSRSDimensionLoc();
     887         203 :             if (pszSRSDimensionLoc != nullptr)
     888           3 :                 papszOptions = CSLSetNameValue(papszOptions, "SRSDIMENSION_LOC",
     889             :                                                pszSRSDimensionLoc);
     890         203 :             if (poDS->IsGML32Output())
     891             :             {
     892         103 :                 if (poFeatureDefn->GetGeomFieldCount() > 1)
     893          18 :                     papszOptions = CSLAddString(
     894             :                         papszOptions, CPLSPrintf("GMLID=%s.%s." CPL_FRMT_GIB,
     895           9 :                                                  poFeatureDefn->GetName(),
     896             :                                                  poFieldDefn->GetNameRef(),
     897             :                                                  poFeature->GetFID()));
     898             :                 else
     899         188 :                     papszOptions = CSLAddString(
     900             :                         papszOptions, CPLSPrintf("GMLID=%s.geom." CPL_FRMT_GIB,
     901          94 :                                                  poFeatureDefn->GetName(),
     902             :                                                  poFeature->GetFID()));
     903             :             }
     904             : 
     905         203 :             if (oCoordPrec.dfXYResolution !=
     906             :                 OGRGeomCoordinatePrecision::UNKNOWN)
     907             :             {
     908           3 :                 papszOptions = CSLAddString(
     909             :                     papszOptions, CPLSPrintf("XY_COORD_RESOLUTION=%g",
     910           3 :                                              oCoordPrec.dfXYResolution));
     911             :             }
     912         203 :             if (oCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
     913             :             {
     914           3 :                 papszOptions = CSLAddString(
     915             :                     papszOptions, CPLSPrintf("Z_COORD_RESOLUTION=%g",
     916           3 :                                              oCoordPrec.dfZResolution));
     917             :             }
     918             : 
     919         203 :             char *pszGeometry = nullptr;
     920         203 :             if (!bIsGML3Output && OGR_GT_IsNonLinear(poGeom->getGeometryType()))
     921             :             {
     922           0 :                 OGRGeometry *poGeomTmp = OGRGeometryFactory::forceTo(
     923           0 :                     poGeom->clone(),
     924           0 :                     OGR_GT_GetLinear(poGeom->getGeometryType()));
     925           0 :                 pszGeometry = poGeomTmp->exportToGML(papszOptions);
     926           0 :                 delete poGeomTmp;
     927             :             }
     928             :             else
     929             :             {
     930         203 :                 if (wkbFlatten(poGeom->getGeometryType()) == wkbTriangle)
     931             :                 {
     932           0 :                     pszGeometry = poGeom->exportToGML(papszOptions);
     933             : 
     934             :                     const char *pszGMLID =
     935           0 :                         poDS->IsGML32Output()
     936           0 :                             ? CPLSPrintf(
     937             :                                   " gml:id=\"%s\"",
     938             :                                   CSLFetchNameValue(papszOptions, "GMLID"))
     939           0 :                             : "";
     940           0 :                     char *pszNewGeom = CPLStrdup(
     941             :                         CPLSPrintf("<gml:TriangulatedSurface%s><gml:patches>%s<"
     942             :                                    "/gml:patches></gml:TriangulatedSurface>",
     943             :                                    pszGMLID, pszGeometry));
     944           0 :                     CPLFree(pszGeometry);
     945           0 :                     pszGeometry = pszNewGeom;
     946             :                 }
     947             :                 else
     948             :                 {
     949         203 :                     pszGeometry = poGeom->exportToGML(papszOptions);
     950             :                 }
     951             :             }
     952         203 :             CSLDestroy(papszOptions);
     953         203 :             if (pszGeometry)
     954             :             {
     955         202 :                 if (bWriteSpaceIndentation)
     956         202 :                     VSIFPrintfL(fp, "      ");
     957         202 :                 if (bRemoveAppPrefix)
     958          20 :                     poDS->PrintLine(fp, "<%s>%s</%s>",
     959             :                                     poFieldDefn->GetNameRef(), pszGeometry,
     960             :                                     poFieldDefn->GetNameRef());
     961             :                 else
     962         182 :                     poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix,
     963             :                                     poFieldDefn->GetNameRef(), pszGeometry,
     964             :                                     pszPrefix, poFieldDefn->GetNameRef());
     965             :             }
     966             :             else
     967             :             {
     968           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
     969             :                          "Export of geometry to GML failed");
     970             :             }
     971         203 :             CPLFree(pszGeometry);
     972             :         }
     973             :     }
     974             : 
     975             :     // Write all "set" fields.
     976         872 :     for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++)
     977             :     {
     978         621 :         if (iField == nGMLIdIndex)
     979          13 :             continue;
     980         608 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
     981             : 
     982         608 :         if (poFeature->IsFieldNull(iField))
     983             :         {
     984           1 :             const char *pszFieldName = poFieldDefn->GetNameRef();
     985             : 
     986           1 :             if (bWriteSpaceIndentation)
     987           1 :                 VSIFPrintfL(fp, "      ");
     988             : 
     989           1 :             if (bRemoveAppPrefix)
     990           0 :                 poDS->PrintLine(fp, "<%s xsi:nil=\"true\"/>", pszFieldName);
     991             :             else
     992           1 :                 poDS->PrintLine(fp, "<%s:%s xsi:nil=\"true\"/>", pszPrefix,
     993             :                                 pszFieldName);
     994             :         }
     995         607 :         else if (poFeature->IsFieldSet(iField))
     996             :         {
     997         500 :             OGRFieldType eType = poFieldDefn->GetType();
     998         500 :             if (eType == OFTStringList)
     999             :             {
    1000           1 :                 char **papszIter = poFeature->GetFieldAsStringList(iField);
    1001           3 :                 while (papszIter != nullptr && *papszIter != nullptr)
    1002             :                 {
    1003           2 :                     char *pszEscaped = OGRGetXML_UTF8_EscapedString(*papszIter);
    1004           2 :                     GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1005             :                                   bRemoveAppPrefix, poFieldDefn, pszEscaped);
    1006           2 :                     CPLFree(pszEscaped);
    1007             : 
    1008           2 :                     papszIter++;
    1009             :                 }
    1010             :             }
    1011         499 :             else if (eType == OFTIntegerList)
    1012             :             {
    1013           2 :                 int nCount = 0;
    1014             :                 const int *panVals =
    1015           2 :                     poFeature->GetFieldAsIntegerList(iField, &nCount);
    1016           2 :                 if (poFieldDefn->GetSubType() == OFSTBoolean)
    1017             :                 {
    1018           3 :                     for (int i = 0; i < nCount; i++)
    1019             :                     {
    1020             :                         // 0 and 1 are OK, but the canonical representation is
    1021             :                         // false and true.
    1022           2 :                         GMLWriteField(poDS, fp, bWriteSpaceIndentation,
    1023             :                                       pszPrefix, bRemoveAppPrefix, poFieldDefn,
    1024           2 :                                       panVals[i] ? "true" : "false");
    1025             :                     }
    1026             :                 }
    1027             :                 else
    1028             :                 {
    1029           3 :                     for (int i = 0; i < nCount; i++)
    1030             :                     {
    1031           2 :                         GMLWriteField(poDS, fp, bWriteSpaceIndentation,
    1032             :                                       pszPrefix, bRemoveAppPrefix, poFieldDefn,
    1033           2 :                                       CPLSPrintf("%d", panVals[i]));
    1034             :                     }
    1035             :                 }
    1036             :             }
    1037         497 :             else if (eType == OFTInteger64List)
    1038             :             {
    1039           2 :                 int nCount = 0;
    1040             :                 const GIntBig *panVals =
    1041           2 :                     poFeature->GetFieldAsInteger64List(iField, &nCount);
    1042           2 :                 if (poFieldDefn->GetSubType() == OFSTBoolean)
    1043             :                 {
    1044           0 :                     for (int i = 0; i < nCount; i++)
    1045             :                     {
    1046             :                         // 0 and 1 are OK, but the canonical representation is
    1047             :                         // false and true.
    1048           0 :                         GMLWriteField(poDS, fp, bWriteSpaceIndentation,
    1049             :                                       pszPrefix, bRemoveAppPrefix, poFieldDefn,
    1050           0 :                                       panVals[i] ? "true" : "false");
    1051             :                     }
    1052             :                 }
    1053             :                 else
    1054             :                 {
    1055           5 :                     for (int i = 0; i < nCount; i++)
    1056             :                     {
    1057           3 :                         GMLWriteField(poDS, fp, bWriteSpaceIndentation,
    1058             :                                       pszPrefix, bRemoveAppPrefix, poFieldDefn,
    1059           3 :                                       CPLSPrintf(CPL_FRMT_GIB, panVals[i]));
    1060             :                     }
    1061             :                 }
    1062             :             }
    1063         495 :             else if (eType == OFTRealList)
    1064             :             {
    1065           1 :                 int nCount = 0;
    1066             :                 const double *padfVals =
    1067           1 :                     poFeature->GetFieldAsDoubleList(iField, &nCount);
    1068           3 :                 for (int i = 0; i < nCount; i++)
    1069             :                 {
    1070           2 :                     char szBuffer[80] = {};
    1071           2 :                     CPLsnprintf(szBuffer, sizeof(szBuffer), "%.15g",
    1072           2 :                                 padfVals[i]);
    1073           2 :                     GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1074             :                                   bRemoveAppPrefix, poFieldDefn, szBuffer);
    1075             :                 }
    1076             :             }
    1077         625 :             else if ((eType == OFTInteger || eType == OFTInteger64) &&
    1078         131 :                      poFieldDefn->GetSubType() == OFSTBoolean)
    1079             :             {
    1080             :                 // 0 and 1 are OK, but the canonical representation is false and
    1081             :                 // true.
    1082           2 :                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1083             :                               bRemoveAppPrefix, poFieldDefn,
    1084           2 :                               (poFeature->GetFieldAsInteger(iField)) ? "true"
    1085             :                                                                      : "false");
    1086             :             }
    1087         492 :             else if (eType == OFTDate)
    1088             :             {
    1089          49 :                 const OGRField *poField = poFeature->GetRawFieldRef(iField);
    1090             :                 const char *pszXML =
    1091          98 :                     CPLSPrintf("%04d-%02d-%02d", poField->Date.Year,
    1092          49 :                                poField->Date.Month, poField->Date.Day);
    1093          49 :                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1094             :                               bRemoveAppPrefix, poFieldDefn, pszXML);
    1095             :             }
    1096         443 :             else if (eType == OFTDateTime)
    1097             :             {
    1098             :                 char *pszXML =
    1099          49 :                     OGRGetXMLDateTime(poFeature->GetRawFieldRef(iField));
    1100          49 :                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1101             :                               bRemoveAppPrefix, poFieldDefn, pszXML);
    1102          49 :                 CPLFree(pszXML);
    1103             :             }
    1104             :             else
    1105             :             {
    1106         394 :                 const char *pszRaw = poFeature->GetFieldAsString(iField);
    1107             : 
    1108         394 :                 char *pszEscaped = OGRGetXML_UTF8_EscapedString(pszRaw);
    1109             : 
    1110         394 :                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1111             :                               bRemoveAppPrefix, poFieldDefn, pszEscaped);
    1112         394 :                 CPLFree(pszEscaped);
    1113             :             }
    1114             :         }
    1115             :     }
    1116             : 
    1117         251 :     if (bWriteSpaceIndentation)
    1118         251 :         VSIFPrintfL(fp, "    ");
    1119         251 :     if (bRemoveAppPrefix)
    1120          20 :         poDS->PrintLine(fp, "</%s>", poFeatureDefn->GetName());
    1121             :     else
    1122         231 :         poDS->PrintLine(fp, "</%s:%s>", pszPrefix, poFeatureDefn->GetName());
    1123         251 :     if (bWriteSpaceIndentation)
    1124         251 :         VSIFPrintfL(fp, "  ");
    1125         251 :     if (bIsGML3Output && !bGMLFeatureCollection)
    1126             :     {
    1127         207 :         if (bRemoveAppPrefix)
    1128          10 :             poDS->PrintLine(fp, "</featureMember>");
    1129             :         else
    1130         197 :             poDS->PrintLine(fp, "</%s:featureMember>", pszPrefix);
    1131             :     }
    1132             :     else
    1133             :     {
    1134          44 :         poDS->PrintLine(fp, "</gml:featureMember>");
    1135             :     }
    1136             : 
    1137         251 :     return OGRERR_NONE;
    1138             : }
    1139             : 
    1140             : /************************************************************************/
    1141             : /*                           TestCapability()                           */
    1142             : /************************************************************************/
    1143             : 
    1144         314 : int OGRGMLLayer::TestCapability(const char *pszCap)
    1145             : 
    1146             : {
    1147         314 :     if (EQUAL(pszCap, OLCSequentialWrite))
    1148          19 :         return bWriter;
    1149             : 
    1150         295 :     else if (EQUAL(pszCap, OLCCreateField))
    1151          18 :         return bWriter && iNextGMLId == 0;
    1152             : 
    1153         277 :     else if (EQUAL(pszCap, OLCCreateGeomField))
    1154           4 :         return bWriter && iNextGMLId == 0;
    1155             : 
    1156         273 :     else if (EQUAL(pszCap, OLCFastGetExtent))
    1157             :     {
    1158           4 :         if (poFClass == nullptr)
    1159           0 :             return FALSE;
    1160             : 
    1161           4 :         double dfXMin = 0.0;
    1162           4 :         double dfXMax = 0.0;
    1163           4 :         double dfYMin = 0.0;
    1164           4 :         double dfYMax = 0.0;
    1165             : 
    1166           4 :         return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
    1167             :     }
    1168             : 
    1169         269 :     else if (EQUAL(pszCap, OLCFastFeatureCount))
    1170             :     {
    1171           1 :         if (poFClass == nullptr || m_poFilterGeom != nullptr ||
    1172           1 :             m_poAttrQuery != nullptr)
    1173           0 :             return FALSE;
    1174             : 
    1175           1 :         return poFClass->GetFeatureCount() != -1;
    1176             :     }
    1177             : 
    1178         268 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
    1179          14 :         return TRUE;
    1180             : 
    1181         254 :     else if (EQUAL(pszCap, OLCCurveGeometries))
    1182         129 :         return poDS->IsGML3Output();
    1183             : 
    1184         125 :     else if (EQUAL(pszCap, OLCZGeometries))
    1185           3 :         return TRUE;
    1186             : 
    1187             :     else
    1188         122 :         return FALSE;
    1189             : }
    1190             : 
    1191             : /************************************************************************/
    1192             : /*                            CreateField()                             */
    1193             : /************************************************************************/
    1194             : 
    1195         181 : OGRErr OGRGMLLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
    1196             : 
    1197             : {
    1198         181 :     if (!bWriter || iNextGMLId != 0)
    1199           0 :         return OGRERR_FAILURE;
    1200             : 
    1201             :     /* -------------------------------------------------------------------- */
    1202             :     /*      Enforce XML naming semantics on element name.                   */
    1203             :     /* -------------------------------------------------------------------- */
    1204         362 :     OGRFieldDefn oCleanCopy(poField);
    1205         181 :     char *pszName = CPLStrdup(poField->GetNameRef());
    1206         181 :     CPLCleanXMLElementName(pszName);
    1207             : 
    1208         181 :     if (strcmp(pszName, poField->GetNameRef()) != 0)
    1209             :     {
    1210           0 :         if (!bApproxOK)
    1211             :         {
    1212           0 :             CPLFree(pszName);
    1213           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1214             :                      "Unable to create field with name '%s', it would not\n"
    1215             :                      "be valid as an XML element name.",
    1216             :                      poField->GetNameRef());
    1217           0 :             return OGRERR_FAILURE;
    1218             :         }
    1219             : 
    1220           0 :         oCleanCopy.SetName(pszName);
    1221           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1222             :                  "Field name '%s' adjusted to '%s' to be a valid\n"
    1223             :                  "XML element name.",
    1224             :                  poField->GetNameRef(), pszName);
    1225             :     }
    1226             : 
    1227         181 :     CPLFree(pszName);
    1228             : 
    1229         181 :     poFeatureDefn->AddFieldDefn(&oCleanCopy);
    1230             : 
    1231         181 :     return OGRERR_NONE;
    1232             : }
    1233             : 
    1234             : /************************************************************************/
    1235             : /*                          CreateGeomField()                           */
    1236             : /************************************************************************/
    1237             : 
    1238          17 : OGRErr OGRGMLLayer::CreateGeomField(const OGRGeomFieldDefn *poField,
    1239             :                                     int bApproxOK)
    1240             : 
    1241             : {
    1242          17 :     if (!bWriter || iNextGMLId != 0)
    1243           0 :         return OGRERR_FAILURE;
    1244             : 
    1245             :     /* -------------------------------------------------------------------- */
    1246             :     /*      Enforce XML naming semantics on element name.                   */
    1247             :     /* -------------------------------------------------------------------- */
    1248          34 :     OGRGeomFieldDefn oCleanCopy(poField);
    1249          17 :     auto poSRSOri = poField->GetSpatialRef();
    1250          17 :     if (poSRSOri)
    1251             :     {
    1252           5 :         auto poSRS = poSRSOri->Clone();
    1253           5 :         poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1254           5 :         oCleanCopy.SetSpatialRef(poSRS);
    1255           5 :         poSRS->Release();
    1256             :     }
    1257          17 :     char *pszName = CPLStrdup(poField->GetNameRef());
    1258          17 :     CPLCleanXMLElementName(pszName);
    1259             : 
    1260          17 :     if (strcmp(pszName, poField->GetNameRef()) != 0)
    1261             :     {
    1262           0 :         if (!bApproxOK)
    1263             :         {
    1264           0 :             CPLFree(pszName);
    1265           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1266             :                      "Unable to create field with name '%s', it would not\n"
    1267             :                      "be valid as an XML element name.",
    1268             :                      poField->GetNameRef());
    1269           0 :             return OGRERR_FAILURE;
    1270             :         }
    1271             : 
    1272           0 :         oCleanCopy.SetName(pszName);
    1273           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1274             :                  "Field name '%s' adjusted to '%s' to be a valid\n"
    1275             :                  "XML element name.",
    1276             :                  poField->GetNameRef(), pszName);
    1277             :     }
    1278             : 
    1279          17 :     CPLFree(pszName);
    1280             : 
    1281          17 :     poFeatureDefn->AddGeomFieldDefn(&oCleanCopy);
    1282             : 
    1283          17 :     return OGRERR_NONE;
    1284             : }
    1285             : 
    1286             : /************************************************************************/
    1287             : /*                             GetDataset()                             */
    1288             : /************************************************************************/
    1289             : 
    1290          18 : GDALDataset *OGRGMLLayer::GetDataset()
    1291             : {
    1292          18 :     return poDS;
    1293             : }

Generated by: LCOV version 1.14