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

Generated by: LCOV version 1.14