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: 2025-02-20 10:14:44 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         681 : OGRGMLLayer::OGRGMLLayer(const char *pszName, bool bWriterIn,
      27         681 :                          OGRGMLDataSource *poDSIn)
      28             :     : poFeatureDefn(new OGRFeatureDefn(
      29         681 :           pszName + (STARTS_WITH_CI(pszName, "ogr:") ? 4 : 0))),
      30             :       iNextGMLId(0), bInvalidFIDFound(false), pszFIDPrefix(nullptr),
      31             :       bWriter(bWriterIn), poDS(poDSIn),
      32         681 :       poFClass(!bWriter ? poDS->GetReader()->GetClass(pszName) : nullptr),
      33             :       // Reader's should get the corresponding GMLFeatureClass and cache it.
      34        1362 :       hCacheSRS(GML_BuildOGRGeometryFromList_CreateCache()),
      35             :       // Compatibility option. Not advertized, because hopefully won't be
      36             :       // needed. Just put here in case.
      37             :       bUseOldFIDFormat(
      38         681 :           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        2724 :           CPLTestBool(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO")))
      43             : {
      44         681 :     SetDescription(poFeatureDefn->GetName());
      45         681 :     poFeatureDefn->Reference();
      46         681 :     poFeatureDefn->SetGeomType(wkbNone);
      47         681 : }
      48             : 
      49             : /************************************************************************/
      50             : /*                           ~OGRGMLLayer()                           */
      51             : /************************************************************************/
      52             : 
      53        1362 : OGRGMLLayer::~OGRGMLLayer()
      54             : 
      55             : {
      56         681 :     CPLFree(pszFIDPrefix);
      57             : 
      58         681 :     if (poFeatureDefn)
      59         681 :         poFeatureDefn->Release();
      60             : 
      61         681 :     GML_BuildOGRGeometryFromList_DestroyCache(hCacheSRS);
      62        1362 : }
      63             : 
      64             : /************************************************************************/
      65             : /*                            ResetReading()                            */
      66             : /************************************************************************/
      67             : 
      68         750 : void OGRGMLLayer::ResetReading()
      69             : 
      70             : {
      71         750 :     if (bWriter)
      72          16 :         return;
      73             : 
      74        1468 :     if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
      75         734 :         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          94 :         if (iNextGMLId == 0 && poDS->PeekStoredGMLFeature() != nullptr &&
      80           0 :             poDS->PeekStoredGMLFeature()->GetClass() == poFClass)
      81           0 :             return;
      82             : 
      83          94 :         delete poDS->PeekStoredGMLFeature();
      84          94 :         poDS->SetStoredGMLFeature(nullptr);
      85             :     }
      86             : 
      87         734 :     iNextGMLId = 0;
      88         734 :     poDS->GetReader()->ResetReading();
      89         734 :     CPLDebug("GML", "ResetReading()");
      90         734 :     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         563 : static GIntBig Increment(GIntBig nVal)
     105             : {
     106         563 :     if (nVal <= GINTBIG_MAX - 1)
     107         563 :         return nVal + 1;
     108           0 :     return nVal;
     109             : }
     110             : 
     111             : /************************************************************************/
     112             : /*                           GetNextFeature()                           */
     113             : /************************************************************************/
     114             : 
     115         824 : OGRFeature *OGRGMLLayer::GetNextFeature()
     116             : 
     117             : {
     118         824 :     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         808 :     if (poDS->GetLastReadLayer() != this)
     126             :     {
     127         380 :         if (poDS->GetReadMode() != INTERLEAVED_LAYERS)
     128         371 :             ResetReading();
     129         380 :         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        1466 :         GMLFeature *poGMLFeature = poDS->PeekStoredGMLFeature();
     139        1466 :         if (poGMLFeature != nullptr)
     140             :         {
     141           3 :             poDS->SetStoredGMLFeature(nullptr);
     142             :         }
     143             :         else
     144             :         {
     145        1463 :             poGMLFeature = poDS->GetReader()->NextFeature();
     146        1463 :             if (poGMLFeature == nullptr)
     147         808 :                 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        1334 :             m_nFeaturesRead++;
     153             :         }
     154             : 
     155             :         /* --------------------------------------------------------------------
     156             :          */
     157             :         /*      Is it of the proper feature class? */
     158             :         /* --------------------------------------------------------------------
     159             :          */
     160             : 
     161        1337 :         if (poGMLFeature->GetClass() != poFClass)
     162             :         {
     163        1836 :             if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
     164        1222 :                 (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         610 :                 delete poGMLFeature;
     173         610 :                 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         723 :         GIntBig nFID = -1;
     189         723 :         const char *pszGML_FID = poGMLFeature->GetFID();
     190         723 :         if (bInvalidFIDFound)
     191             :         {
     192          44 :             nFID = iNextGMLId;
     193          44 :             iNextGMLId = Increment(iNextGMLId);
     194             :         }
     195         679 :         else if (pszGML_FID == nullptr)
     196             :         {
     197         109 :             bInvalidFIDFound = true;
     198         109 :             nFID = iNextGMLId;
     199         109 :             iNextGMLId = Increment(iNextGMLId);
     200             :         }
     201         570 :         else if (iNextGMLId == 0)
     202             :         {
     203         293 :             int j = 0;
     204         293 :             int i = static_cast<int>(strlen(pszGML_FID)) - 1;
     205         710 :             while (i >= 0 && pszGML_FID[i] >= '0' && pszGML_FID[i] <= '9' &&
     206             :                    j < 20)
     207             :             {
     208         417 :                 i--;
     209         417 :                 j++;
     210             :             }
     211             :             // i points the last character of the fid.
     212         293 :             if (i >= 0 && j < 20 && pszFIDPrefix == nullptr)
     213             :             {
     214         230 :                 pszFIDPrefix = static_cast<char *>(CPLMalloc(i + 2));
     215         230 :                 pszFIDPrefix[i + 1] = '\0';
     216         230 :                 strncpy(pszFIDPrefix, pszGML_FID, i + 1);
     217             :             }
     218             :             // pszFIDPrefix now contains the prefix or NULL if no prefix is
     219             :             // found.
     220         293 :             if (j < 20 && sscanf(pszGML_FID + i + 1, CPL_FRMT_GIB, &nFID) == 1)
     221             :             {
     222         284 :                 if (iNextGMLId <= nFID)
     223         284 :                     iNextGMLId = Increment(nFID);
     224             :             }
     225             :             else
     226             :             {
     227           9 :                 bInvalidFIDFound = true;
     228           9 :                 nFID = iNextGMLId;
     229           9 :                 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         723 :         OGRGeometry **papoGeometries = nullptr;
     264         723 :         const CPLXMLNode *const *papsGeometry = poGMLFeature->GetGeometryList();
     265             : 
     266         723 :         const CPLXMLNode *apsGeometries[2] = {nullptr, nullptr};
     267             :         const CPLXMLNode *psBoundedByGeometry =
     268         723 :             poGMLFeature->GetBoundedByGeometry();
     269         723 :         if (psBoundedByGeometry && !(papsGeometry && papsGeometry[0]))
     270             :         {
     271           6 :             apsGeometries[0] = psBoundedByGeometry;
     272           6 :             papsGeometry = apsGeometries;
     273             :         }
     274             : 
     275         723 :         OGRGeometry *poGeom = nullptr;
     276             : 
     277         723 :         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         629 :         else if (papsGeometry[0] &&
     336         531 :                  strcmp(papsGeometry[0]->pszValue, "null") == 0)
     337             :         {
     338             :             // do nothing
     339             :         }
     340         625 :         else if (papsGeometry[0] != nullptr)
     341             :         {
     342         527 :             const char *pszSRSName = poDS->GetGlobalSRSName();
     343         527 :             CPLPushErrorHandler(CPLQuietErrorHandler);
     344         527 :             poGeom = GML_BuildOGRGeometryFromList(
     345         527 :                 papsGeometry, true, poDS->GetInvertAxisOrderIfLatLong(),
     346         527 :                 pszSRSName, poDS->GetConsiderEPSGAsURN(),
     347         527 :                 poDS->GetSwapCoordinates(), poDS->GetSecondaryGeometryOption(),
     348         527 :                 hCacheSRS, bFaceHoleNegative);
     349         527 :             CPLPopErrorHandler();
     350             : 
     351             :             // Do geometry type changes if needed to match layer geometry type.
     352         527 :             if (poGeom != nullptr)
     353             :             {
     354         527 :                 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         527 :             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         703 :         int iDstField = 0;
     393         703 :         OGRFeature *poOGRFeature = new OGRFeature(poFeatureDefn);
     394             : 
     395         703 :         poOGRFeature->SetFID(nFID);
     396         703 :         if (poDS->ExposeId())
     397             :         {
     398         595 :             if (pszGML_FID)
     399         558 :                 poOGRFeature->SetField(iDstField, pszGML_FID);
     400         595 :             iDstField++;
     401             :         }
     402             : 
     403         703 :         const int nPropertyCount = poFClass->GetPropertyCount();
     404        3430 :         for (int iField = 0; iField < nPropertyCount; iField++, iDstField++)
     405             :         {
     406             :             const GMLProperty *psGMLProperty =
     407        2727 :                 poGMLFeature->GetProperty(iField);
     408        2727 :             if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
     409         614 :                 continue;
     410             : 
     411        2113 :             if (EQUAL(psGMLProperty->papszSubProperties[0], OGR_GML_NULL))
     412             :             {
     413           8 :                 poOGRFeature->SetFieldNull(iDstField);
     414           8 :                 continue;
     415             :             }
     416             : 
     417        2105 :             switch (poFClass->GetProperty(iField)->GetType())
     418             :             {
     419         354 :                 case GMLPT_Real:
     420             :                 {
     421         354 :                     poOGRFeature->SetField(
     422             :                         iDstField,
     423         354 :                         CPLAtof(psGMLProperty->papszSubProperties[0]));
     424             :                 }
     425         354 :                 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        1552 :                 default:
     524        1552 :                     poOGRFeature->SetField(
     525        1552 :                         iDstField, psGMLProperty->papszSubProperties[0]);
     526        1552 :                     break;
     527             :             }
     528             :         }
     529             : 
     530         703 :         delete poGMLFeature;
     531         703 :         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         703 :         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         609 :             poOGRFeature->SetGeometryDirectly(poGeom);
     547             :         }
     548             : 
     549             :         // Assign SRS.
     550        1460 :         for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
     551             :         {
     552         757 :             poGeom = poOGRFeature->GetGeomFieldRef(i);
     553         757 :             if (poGeom != nullptr)
     554             :             {
     555             :                 const OGRSpatialReference *poSRS =
     556         670 :                     poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef();
     557         670 :                 if (poSRS != nullptr)
     558         137 :                     poGeom->assignSpatialReference(poSRS);
     559             :             }
     560             :         }
     561             : 
     562             :         /* --------------------------------------------------------------------
     563             :          */
     564             :         /*      Test against the attribute query. */
     565             :         /* --------------------------------------------------------------------
     566             :          */
     567         703 :         if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
     568             :         {
     569          28 :             delete poOGRFeature;
     570          28 :             continue;
     571             :         }
     572             : 
     573             :         // Got the desired feature.
     574         675 :         return poOGRFeature;
     575         658 :     }
     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             : /*                            IGetExtent()                              */
     607             : /************************************************************************/
     608             : 
     609          10 : OGRErr OGRGMLLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     610             :                                bool bForce)
     611             : 
     612             : {
     613          10 :     if (GetGeomType() == wkbNone)
     614           0 :         return OGRERR_FAILURE;
     615             : 
     616          10 :     double dfXMin = 0.0;
     617          10 :     double dfXMax = 0.0;
     618          10 :     double dfYMin = 0.0;
     619          10 :     double dfYMax = 0.0;
     620          20 :     if (poFClass != nullptr &&
     621          10 :         poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax))
     622             :     {
     623           8 :         psExtent->MinX = dfXMin;
     624           8 :         psExtent->MaxX = dfXMax;
     625           8 :         psExtent->MinY = dfYMin;
     626           8 :         psExtent->MaxY = dfYMax;
     627             : 
     628           8 :         return OGRERR_NONE;
     629             :     }
     630             : 
     631           2 :     return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     632             : }
     633             : 
     634             : /************************************************************************/
     635             : /*                             GetExtent()                              */
     636             : /************************************************************************/
     637             : 
     638         505 : static void GMLWriteField(OGRGMLDataSource *poDS, VSILFILE *fp,
     639             :                           bool bWriteSpaceIndentation, const char *pszPrefix,
     640             :                           bool bRemoveAppPrefix, OGRFieldDefn *poFieldDefn,
     641             :                           const char *pszVal)
     642             : 
     643             : {
     644         505 :     const char *pszFieldName = poFieldDefn->GetNameRef();
     645             : 
     646         505 :     while (*pszVal == ' ')
     647           0 :         pszVal++;
     648             : 
     649         505 :     if (bWriteSpaceIndentation)
     650         505 :         VSIFPrintfL(fp, "      ");
     651             : 
     652         505 :     if (bRemoveAppPrefix)
     653          60 :         poDS->PrintLine(fp, "<%s>%s</%s>", pszFieldName, pszVal, pszFieldName);
     654             :     else
     655         445 :         poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix, pszFieldName,
     656             :                         pszVal, pszPrefix, pszFieldName);
     657         505 : }
     658             : 
     659             : /************************************************************************/
     660             : /*                           ICreateFeature()                            */
     661             : /************************************************************************/
     662             : 
     663         266 : OGRErr OGRGMLLayer::ICreateFeature(OGRFeature *poFeature)
     664             : 
     665             : {
     666         266 :     const bool bIsGML3Output = poDS->IsGML3Output();
     667         266 :     VSILFILE *fp = poDS->GetOutputFP();
     668         266 :     const bool bWriteSpaceIndentation = poDS->WriteSpaceIndentation();
     669         266 :     const char *pszPrefix = poDS->GetAppPrefix();
     670         266 :     const bool bRemoveAppPrefix = poDS->RemoveAppPrefix();
     671         266 :     const bool bGMLFeatureCollection = poDS->GMLFeatureCollection();
     672             : 
     673         266 :     if (!bWriter || poDS->HasWriteError())
     674           0 :         return OGRERR_FAILURE;
     675             : 
     676         266 :     poFeature->FillUnsetWithDefault(TRUE, nullptr);
     677         266 :     if (!poFeature->Validate(OGR_F_VAL_ALL & ~OGR_F_VAL_GEOM_TYPE &
     678             :                                  ~OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT,
     679             :                              TRUE))
     680           2 :         return OGRERR_FAILURE;
     681             : 
     682         264 :     if (bWriteSpaceIndentation)
     683         264 :         VSIFPrintfL(fp, "  ");
     684         264 :     if (bIsGML3Output && !bGMLFeatureCollection)
     685             :     {
     686         220 :         if (bRemoveAppPrefix)
     687          10 :             poDS->PrintLine(fp, "<featureMember>");
     688             :         else
     689         210 :             poDS->PrintLine(fp, "<%s:featureMember>", pszPrefix);
     690             :     }
     691             :     else
     692             :     {
     693          44 :         poDS->PrintLine(fp, "<gml:featureMember>");
     694             :     }
     695             : 
     696         264 :     if (poFeature->GetFID() == OGRNullFID)
     697         251 :         poFeature->SetFID(iNextGMLId++);
     698             : 
     699         264 :     if (bWriteSpaceIndentation)
     700         264 :         VSIFPrintfL(fp, "    ");
     701         264 :     VSIFPrintfL(fp, "<");
     702         264 :     if (!bRemoveAppPrefix)
     703         244 :         VSIFPrintfL(fp, "%s:", pszPrefix);
     704             : 
     705         264 :     int nGMLIdIndex = -1;
     706         264 :     if (bIsGML3Output)
     707             :     {
     708         230 :         nGMLIdIndex = poFeatureDefn->GetFieldIndex("gml_id");
     709         230 :         if (nGMLIdIndex >= 0 && poFeature->IsFieldSetAndNotNull(nGMLIdIndex))
     710           3 :             poDS->PrintLine(fp, "%s gml:id=\"%s\">", poFeatureDefn->GetName(),
     711             :                             poFeature->GetFieldAsString(nGMLIdIndex));
     712             :         else
     713         454 :             poDS->PrintLine(fp, "%s gml:id=\"%s." CPL_FRMT_GIB "\">",
     714         227 :                             poFeatureDefn->GetName(), poFeatureDefn->GetName(),
     715             :                             poFeature->GetFID());
     716             :     }
     717             :     else
     718             :     {
     719          34 :         nGMLIdIndex = poFeatureDefn->GetFieldIndex("fid");
     720          34 :         if (bUseOldFIDFormat)
     721             :         {
     722           0 :             poDS->PrintLine(fp, "%s fid=\"F" CPL_FRMT_GIB "\">",
     723           0 :                             poFeatureDefn->GetName(), poFeature->GetFID());
     724             :         }
     725          44 :         else if (nGMLIdIndex >= 0 &&
     726          10 :                  poFeature->IsFieldSetAndNotNull(nGMLIdIndex))
     727             :         {
     728          10 :             poDS->PrintLine(fp, "%s fid=\"%s\">", poFeatureDefn->GetName(),
     729             :                             poFeature->GetFieldAsString(nGMLIdIndex));
     730             :         }
     731             :         else
     732             :         {
     733          48 :             poDS->PrintLine(fp, "%s fid=\"%s." CPL_FRMT_GIB "\">",
     734          24 :                             poFeatureDefn->GetName(), poFeatureDefn->GetName(),
     735             :                             poFeature->GetFID());
     736             :         }
     737             :     }
     738             : 
     739         517 :     for (int iGeomField = 0; iGeomField < poFeatureDefn->GetGeomFieldCount();
     740             :          iGeomField++)
     741             :     {
     742             :         const OGRGeomFieldDefn *poFieldDefn =
     743         253 :             poFeatureDefn->GetGeomFieldDefn(iGeomField);
     744             : 
     745             :         // Write out Geometry - for now it isn't indented properly.
     746             :         // GML geometries don't like very much the concept of empty geometry.
     747         253 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
     748         253 :         if (poGeom != nullptr && !poGeom->IsEmpty())
     749             :         {
     750         215 :             OGREnvelope3D sGeomBounds;
     751             : 
     752         215 :             const int nCoordDimension = poGeom->getCoordinateDimension();
     753             : 
     754         215 :             poGeom->getEnvelope(&sGeomBounds);
     755         215 :             if (poDS->HasWriteGlobalSRS())
     756         211 :                 poDS->GrowExtents(&sGeomBounds, nCoordDimension);
     757             : 
     758         356 :             if (poGeom->getSpatialReference() == nullptr &&
     759         141 :                 poFieldDefn->GetSpatialRef() != nullptr)
     760          18 :                 poGeom->assignSpatialReference(poFieldDefn->GetSpatialRef());
     761             : 
     762         215 :             const auto &oCoordPrec = poFieldDefn->GetCoordinatePrecision();
     763             : 
     764         215 :             if (bIsGML3Output && poDS->WriteFeatureBoundedBy())
     765             :             {
     766         171 :                 bool bCoordSwap = false;
     767             : 
     768             :                 char *pszSRSName =
     769         171 :                     GML_GetSRSName(poGeom->getSpatialReference(),
     770         171 :                                    poDS->GetSRSNameFormat(), &bCoordSwap);
     771         171 :                 char szLowerCorner[75] = {};
     772         171 :                 char szUpperCorner[75] = {};
     773             : 
     774         171 :                 OGRWktOptions coordOpts;
     775             : 
     776         171 :                 if (oCoordPrec.dfXYResolution !=
     777             :                     OGRGeomCoordinatePrecision::UNKNOWN)
     778             :                 {
     779           3 :                     coordOpts.format = OGRWktFormat::F;
     780           3 :                     coordOpts.xyPrecision =
     781           3 :                         OGRGeomCoordinatePrecision::ResolutionToPrecision(
     782           3 :                             oCoordPrec.dfXYResolution);
     783             :                 }
     784         171 :                 if (oCoordPrec.dfZResolution !=
     785             :                     OGRGeomCoordinatePrecision::UNKNOWN)
     786             :                 {
     787           3 :                     coordOpts.format = OGRWktFormat::F;
     788           3 :                     coordOpts.zPrecision =
     789           3 :                         OGRGeomCoordinatePrecision::ResolutionToPrecision(
     790           3 :                             oCoordPrec.dfZResolution);
     791             :                 }
     792             : 
     793         342 :                 std::string wkt;
     794         171 :                 if (bCoordSwap)
     795             :                 {
     796          36 :                     wkt = OGRMakeWktCoordinate(
     797             :                         sGeomBounds.MinY, sGeomBounds.MinX, sGeomBounds.MinZ,
     798          18 :                         nCoordDimension, coordOpts);
     799          18 :                     memcpy(szLowerCorner, wkt.data(), wkt.size() + 1);
     800             : 
     801          36 :                     wkt = OGRMakeWktCoordinate(
     802             :                         sGeomBounds.MaxY, sGeomBounds.MaxX, sGeomBounds.MaxZ,
     803          18 :                         nCoordDimension, coordOpts);
     804          18 :                     memcpy(szUpperCorner, wkt.data(), wkt.size() + 1);
     805             :                 }
     806             :                 else
     807             :                 {
     808         306 :                     wkt = OGRMakeWktCoordinate(
     809             :                         sGeomBounds.MinX, sGeomBounds.MinY, sGeomBounds.MinZ,
     810         153 :                         nCoordDimension, coordOpts);
     811         153 :                     memcpy(szLowerCorner, wkt.data(), wkt.size() + 1);
     812             : 
     813         306 :                     wkt = OGRMakeWktCoordinate(
     814             :                         sGeomBounds.MaxX, sGeomBounds.MaxY, sGeomBounds.MaxZ,
     815         153 :                         nCoordDimension, coordOpts);
     816         153 :                     memcpy(szUpperCorner, wkt.data(), wkt.size() + 1);
     817             :                 }
     818         171 :                 if (bWriteSpaceIndentation)
     819         171 :                     VSIFPrintfL(fp, "      ");
     820         171 :                 poDS->PrintLine(
     821             :                     fp,
     822             :                     "<gml:boundedBy><gml:Envelope%s%s><gml:lowerCorner>%s"
     823             :                     "</gml:lowerCorner><gml:upperCorner>%s</gml:upperCorner>"
     824             :                     "</gml:Envelope></gml:boundedBy>",
     825             :                     (nCoordDimension == 3) ? " srsDimension=\"3\"" : "",
     826             :                     pszSRSName, szLowerCorner, szUpperCorner);
     827         171 :                 CPLFree(pszSRSName);
     828             :             }
     829             : 
     830         215 :             char **papszOptions = nullptr;
     831         215 :             if (bIsGML3Output)
     832             :             {
     833         181 :                 papszOptions = CSLAddString(papszOptions, "FORMAT=GML3");
     834         181 :                 if (poDS->GetSRSNameFormat() == SRSNAME_SHORT)
     835             :                     papszOptions =
     836           1 :                         CSLAddString(papszOptions, "SRSNAME_FORMAT=SHORT");
     837         180 :                 else if (poDS->GetSRSNameFormat() == SRSNAME_OGC_URN)
     838             :                     papszOptions =
     839         167 :                         CSLAddString(papszOptions, "SRSNAME_FORMAT=OGC_URN");
     840          13 :                 else if (poDS->GetSRSNameFormat() == SRSNAME_OGC_URL)
     841             :                     papszOptions =
     842          13 :                         CSLAddString(papszOptions, "SRSNAME_FORMAT=OGC_URL");
     843             :             }
     844         215 :             const char *pszSRSDimensionLoc = poDS->GetSRSDimensionLoc();
     845         215 :             if (pszSRSDimensionLoc != nullptr)
     846           3 :                 papszOptions = CSLSetNameValue(papszOptions, "SRSDIMENSION_LOC",
     847             :                                                pszSRSDimensionLoc);
     848         215 :             if (poDS->IsGML32Output())
     849             :             {
     850         115 :                 if (poFeatureDefn->GetGeomFieldCount() > 1)
     851          18 :                     papszOptions = CSLAddString(
     852             :                         papszOptions, CPLSPrintf("GMLID=%s.%s." CPL_FRMT_GIB,
     853           9 :                                                  poFeatureDefn->GetName(),
     854             :                                                  poFieldDefn->GetNameRef(),
     855             :                                                  poFeature->GetFID()));
     856             :                 else
     857         212 :                     papszOptions = CSLAddString(
     858             :                         papszOptions, CPLSPrintf("GMLID=%s.geom." CPL_FRMT_GIB,
     859         106 :                                                  poFeatureDefn->GetName(),
     860             :                                                  poFeature->GetFID()));
     861             :             }
     862             : 
     863         215 :             if (oCoordPrec.dfXYResolution !=
     864             :                 OGRGeomCoordinatePrecision::UNKNOWN)
     865             :             {
     866           3 :                 papszOptions = CSLAddString(
     867             :                     papszOptions, CPLSPrintf("XY_COORD_RESOLUTION=%g",
     868           3 :                                              oCoordPrec.dfXYResolution));
     869             :             }
     870         215 :             if (oCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
     871             :             {
     872           3 :                 papszOptions = CSLAddString(
     873             :                     papszOptions, CPLSPrintf("Z_COORD_RESOLUTION=%g",
     874           3 :                                              oCoordPrec.dfZResolution));
     875             :             }
     876             : 
     877         215 :             char *pszGeometry = nullptr;
     878         215 :             if (!bIsGML3Output && OGR_GT_IsNonLinear(poGeom->getGeometryType()))
     879             :             {
     880           0 :                 OGRGeometry *poGeomTmp = OGRGeometryFactory::forceTo(
     881           0 :                     poGeom->clone(),
     882           0 :                     OGR_GT_GetLinear(poGeom->getGeometryType()));
     883           0 :                 pszGeometry = poGeomTmp->exportToGML(papszOptions);
     884           0 :                 delete poGeomTmp;
     885             :             }
     886             :             else
     887             :             {
     888         215 :                 if (wkbFlatten(poGeom->getGeometryType()) == wkbTriangle)
     889             :                 {
     890           0 :                     pszGeometry = poGeom->exportToGML(papszOptions);
     891             : 
     892             :                     const char *pszGMLID =
     893           0 :                         poDS->IsGML32Output()
     894           0 :                             ? CPLSPrintf(
     895             :                                   " gml:id=\"%s\"",
     896             :                                   CSLFetchNameValue(papszOptions, "GMLID"))
     897           0 :                             : "";
     898           0 :                     char *pszNewGeom = CPLStrdup(
     899             :                         CPLSPrintf("<gml:TriangulatedSurface%s><gml:patches>%s<"
     900             :                                    "/gml:patches></gml:TriangulatedSurface>",
     901             :                                    pszGMLID, pszGeometry));
     902           0 :                     CPLFree(pszGeometry);
     903           0 :                     pszGeometry = pszNewGeom;
     904             :                 }
     905             :                 else
     906             :                 {
     907         215 :                     pszGeometry = poGeom->exportToGML(papszOptions);
     908             :                 }
     909             :             }
     910         215 :             CSLDestroy(papszOptions);
     911         215 :             if (pszGeometry)
     912             :             {
     913         214 :                 if (bWriteSpaceIndentation)
     914         214 :                     VSIFPrintfL(fp, "      ");
     915         214 :                 if (bRemoveAppPrefix)
     916          20 :                     poDS->PrintLine(fp, "<%s>%s</%s>",
     917             :                                     poFieldDefn->GetNameRef(), pszGeometry,
     918             :                                     poFieldDefn->GetNameRef());
     919             :                 else
     920         194 :                     poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix,
     921             :                                     poFieldDefn->GetNameRef(), pszGeometry,
     922             :                                     pszPrefix, poFieldDefn->GetNameRef());
     923             :             }
     924             :             else
     925             :             {
     926           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
     927             :                          "Export of geometry to GML failed");
     928             :             }
     929         215 :             CPLFree(pszGeometry);
     930             :         }
     931             :     }
     932             : 
     933             :     // Write all "set" fields.
     934         885 :     for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++)
     935             :     {
     936         621 :         if (iField == nGMLIdIndex)
     937          13 :             continue;
     938         608 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
     939             : 
     940         608 :         if (poFeature->IsFieldNull(iField))
     941             :         {
     942           1 :             const char *pszFieldName = poFieldDefn->GetNameRef();
     943             : 
     944           1 :             if (bWriteSpaceIndentation)
     945           1 :                 VSIFPrintfL(fp, "      ");
     946             : 
     947           1 :             if (bRemoveAppPrefix)
     948           0 :                 poDS->PrintLine(fp, "<%s xsi:nil=\"true\"/>", pszFieldName);
     949             :             else
     950           1 :                 poDS->PrintLine(fp, "<%s:%s xsi:nil=\"true\"/>", pszPrefix,
     951             :                                 pszFieldName);
     952             :         }
     953         607 :         else if (poFeature->IsFieldSet(iField))
     954             :         {
     955         500 :             OGRFieldType eType = poFieldDefn->GetType();
     956         500 :             if (eType == OFTStringList)
     957             :             {
     958           1 :                 char **papszIter = poFeature->GetFieldAsStringList(iField);
     959           3 :                 while (papszIter != nullptr && *papszIter != nullptr)
     960             :                 {
     961           2 :                     char *pszEscaped = OGRGetXML_UTF8_EscapedString(*papszIter);
     962           2 :                     GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
     963             :                                   bRemoveAppPrefix, poFieldDefn, pszEscaped);
     964           2 :                     CPLFree(pszEscaped);
     965             : 
     966           2 :                     papszIter++;
     967             :                 }
     968             :             }
     969         499 :             else if (eType == OFTIntegerList)
     970             :             {
     971           2 :                 int nCount = 0;
     972             :                 const int *panVals =
     973           2 :                     poFeature->GetFieldAsIntegerList(iField, &nCount);
     974           2 :                 if (poFieldDefn->GetSubType() == OFSTBoolean)
     975             :                 {
     976           3 :                     for (int i = 0; i < nCount; i++)
     977             :                     {
     978             :                         // 0 and 1 are OK, but the canonical representation is
     979             :                         // false and true.
     980           2 :                         GMLWriteField(poDS, fp, bWriteSpaceIndentation,
     981             :                                       pszPrefix, bRemoveAppPrefix, poFieldDefn,
     982           2 :                                       panVals[i] ? "true" : "false");
     983             :                     }
     984             :                 }
     985             :                 else
     986             :                 {
     987           3 :                     for (int i = 0; i < nCount; i++)
     988             :                     {
     989           2 :                         GMLWriteField(poDS, fp, bWriteSpaceIndentation,
     990             :                                       pszPrefix, bRemoveAppPrefix, poFieldDefn,
     991           2 :                                       CPLSPrintf("%d", panVals[i]));
     992             :                     }
     993             :                 }
     994             :             }
     995         497 :             else if (eType == OFTInteger64List)
     996             :             {
     997           2 :                 int nCount = 0;
     998             :                 const GIntBig *panVals =
     999           2 :                     poFeature->GetFieldAsInteger64List(iField, &nCount);
    1000           2 :                 if (poFieldDefn->GetSubType() == OFSTBoolean)
    1001             :                 {
    1002           0 :                     for (int i = 0; i < nCount; i++)
    1003             :                     {
    1004             :                         // 0 and 1 are OK, but the canonical representation is
    1005             :                         // false and true.
    1006           0 :                         GMLWriteField(poDS, fp, bWriteSpaceIndentation,
    1007             :                                       pszPrefix, bRemoveAppPrefix, poFieldDefn,
    1008           0 :                                       panVals[i] ? "true" : "false");
    1009             :                     }
    1010             :                 }
    1011             :                 else
    1012             :                 {
    1013           5 :                     for (int i = 0; i < nCount; i++)
    1014             :                     {
    1015           3 :                         GMLWriteField(poDS, fp, bWriteSpaceIndentation,
    1016             :                                       pszPrefix, bRemoveAppPrefix, poFieldDefn,
    1017           3 :                                       CPLSPrintf(CPL_FRMT_GIB, panVals[i]));
    1018             :                     }
    1019             :                 }
    1020             :             }
    1021         495 :             else if (eType == OFTRealList)
    1022             :             {
    1023           1 :                 int nCount = 0;
    1024             :                 const double *padfVals =
    1025           1 :                     poFeature->GetFieldAsDoubleList(iField, &nCount);
    1026           3 :                 for (int i = 0; i < nCount; i++)
    1027             :                 {
    1028           2 :                     char szBuffer[80] = {};
    1029           2 :                     CPLsnprintf(szBuffer, sizeof(szBuffer), "%.15g",
    1030           2 :                                 padfVals[i]);
    1031           2 :                     GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1032             :                                   bRemoveAppPrefix, poFieldDefn, szBuffer);
    1033             :                 }
    1034             :             }
    1035         625 :             else if ((eType == OFTInteger || eType == OFTInteger64) &&
    1036         131 :                      poFieldDefn->GetSubType() == OFSTBoolean)
    1037             :             {
    1038             :                 // 0 and 1 are OK, but the canonical representation is false and
    1039             :                 // true.
    1040           2 :                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1041             :                               bRemoveAppPrefix, poFieldDefn,
    1042           2 :                               (poFeature->GetFieldAsInteger(iField)) ? "true"
    1043             :                                                                      : "false");
    1044             :             }
    1045         492 :             else if (eType == OFTDate)
    1046             :             {
    1047          49 :                 const OGRField *poField = poFeature->GetRawFieldRef(iField);
    1048             :                 const char *pszXML =
    1049          98 :                     CPLSPrintf("%04d-%02d-%02d", poField->Date.Year,
    1050          49 :                                poField->Date.Month, poField->Date.Day);
    1051          49 :                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1052             :                               bRemoveAppPrefix, poFieldDefn, pszXML);
    1053             :             }
    1054         443 :             else if (eType == OFTDateTime)
    1055             :             {
    1056             :                 char *pszXML =
    1057          49 :                     OGRGetXMLDateTime(poFeature->GetRawFieldRef(iField));
    1058          49 :                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1059             :                               bRemoveAppPrefix, poFieldDefn, pszXML);
    1060          49 :                 CPLFree(pszXML);
    1061             :             }
    1062             :             else
    1063             :             {
    1064         394 :                 const char *pszRaw = poFeature->GetFieldAsString(iField);
    1065             : 
    1066         394 :                 char *pszEscaped = OGRGetXML_UTF8_EscapedString(pszRaw);
    1067             : 
    1068         394 :                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
    1069             :                               bRemoveAppPrefix, poFieldDefn, pszEscaped);
    1070         394 :                 CPLFree(pszEscaped);
    1071             :             }
    1072             :         }
    1073             :     }
    1074             : 
    1075         264 :     if (bWriteSpaceIndentation)
    1076         264 :         VSIFPrintfL(fp, "    ");
    1077         264 :     if (bRemoveAppPrefix)
    1078          20 :         poDS->PrintLine(fp, "</%s>", poFeatureDefn->GetName());
    1079             :     else
    1080         244 :         poDS->PrintLine(fp, "</%s:%s>", pszPrefix, poFeatureDefn->GetName());
    1081         264 :     if (bWriteSpaceIndentation)
    1082         264 :         VSIFPrintfL(fp, "  ");
    1083         264 :     if (bIsGML3Output && !bGMLFeatureCollection)
    1084             :     {
    1085         220 :         if (bRemoveAppPrefix)
    1086          10 :             poDS->PrintLine(fp, "</featureMember>");
    1087             :         else
    1088         210 :             poDS->PrintLine(fp, "</%s:featureMember>", pszPrefix);
    1089             :     }
    1090             :     else
    1091             :     {
    1092          44 :         poDS->PrintLine(fp, "</gml:featureMember>");
    1093             :     }
    1094             : 
    1095         264 :     return !poDS->HasWriteError() ? OGRERR_NONE : OGRERR_FAILURE;
    1096             : }
    1097             : 
    1098             : /************************************************************************/
    1099             : /*                           TestCapability()                           */
    1100             : /************************************************************************/
    1101             : 
    1102         340 : int OGRGMLLayer::TestCapability(const char *pszCap)
    1103             : 
    1104             : {
    1105         340 :     if (EQUAL(pszCap, OLCSequentialWrite))
    1106          19 :         return bWriter;
    1107             : 
    1108         321 :     else if (EQUAL(pszCap, OLCCreateField))
    1109          18 :         return bWriter && iNextGMLId == 0;
    1110             : 
    1111         303 :     else if (EQUAL(pszCap, OLCCreateGeomField))
    1112           4 :         return bWriter && iNextGMLId == 0;
    1113             : 
    1114         299 :     else if (EQUAL(pszCap, OLCFastGetExtent))
    1115             :     {
    1116           4 :         if (poFClass == nullptr)
    1117           0 :             return FALSE;
    1118             : 
    1119           4 :         double dfXMin = 0.0;
    1120           4 :         double dfXMax = 0.0;
    1121           4 :         double dfYMin = 0.0;
    1122           4 :         double dfYMax = 0.0;
    1123             : 
    1124           4 :         return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
    1125             :     }
    1126             : 
    1127         295 :     else if (EQUAL(pszCap, OLCFastFeatureCount))
    1128             :     {
    1129           1 :         if (poFClass == nullptr || m_poFilterGeom != nullptr ||
    1130           1 :             m_poAttrQuery != nullptr)
    1131           0 :             return FALSE;
    1132             : 
    1133           1 :         return poFClass->GetFeatureCount() != -1;
    1134             :     }
    1135             : 
    1136         294 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
    1137          14 :         return TRUE;
    1138             : 
    1139         280 :     else if (EQUAL(pszCap, OLCCurveGeometries))
    1140         146 :         return poDS->IsGML3Output();
    1141             : 
    1142         134 :     else if (EQUAL(pszCap, OLCZGeometries))
    1143           3 :         return TRUE;
    1144             : 
    1145             :     else
    1146         131 :         return FALSE;
    1147             : }
    1148             : 
    1149             : /************************************************************************/
    1150             : /*                            CreateField()                             */
    1151             : /************************************************************************/
    1152             : 
    1153         181 : OGRErr OGRGMLLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
    1154             : 
    1155             : {
    1156         181 :     if (!bWriter || iNextGMLId != 0)
    1157           0 :         return OGRERR_FAILURE;
    1158             : 
    1159             :     /* -------------------------------------------------------------------- */
    1160             :     /*      Enforce XML naming semantics on element name.                   */
    1161             :     /* -------------------------------------------------------------------- */
    1162         362 :     OGRFieldDefn oCleanCopy(poField);
    1163         181 :     char *pszName = CPLStrdup(poField->GetNameRef());
    1164         181 :     CPLCleanXMLElementName(pszName);
    1165             : 
    1166         181 :     if (strcmp(pszName, poField->GetNameRef()) != 0)
    1167             :     {
    1168           0 :         if (!bApproxOK)
    1169             :         {
    1170           0 :             CPLFree(pszName);
    1171           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1172             :                      "Unable to create field with name '%s', it would not\n"
    1173             :                      "be valid as an XML element name.",
    1174             :                      poField->GetNameRef());
    1175           0 :             return OGRERR_FAILURE;
    1176             :         }
    1177             : 
    1178           0 :         oCleanCopy.SetName(pszName);
    1179           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1180             :                  "Field name '%s' adjusted to '%s' to be a valid\n"
    1181             :                  "XML element name.",
    1182             :                  poField->GetNameRef(), pszName);
    1183             :     }
    1184             : 
    1185         181 :     CPLFree(pszName);
    1186             : 
    1187         181 :     poFeatureDefn->AddFieldDefn(&oCleanCopy);
    1188             : 
    1189         181 :     return OGRERR_NONE;
    1190             : }
    1191             : 
    1192             : /************************************************************************/
    1193             : /*                          CreateGeomField()                           */
    1194             : /************************************************************************/
    1195             : 
    1196          19 : OGRErr OGRGMLLayer::CreateGeomField(const OGRGeomFieldDefn *poField,
    1197             :                                     int bApproxOK)
    1198             : 
    1199             : {
    1200          19 :     if (!bWriter || iNextGMLId != 0)
    1201           0 :         return OGRERR_FAILURE;
    1202             : 
    1203             :     /* -------------------------------------------------------------------- */
    1204             :     /*      Enforce XML naming semantics on element name.                   */
    1205             :     /* -------------------------------------------------------------------- */
    1206          38 :     OGRGeomFieldDefn oCleanCopy(poField);
    1207          19 :     const auto poSRSOri = poField->GetSpatialRef();
    1208          19 :     poDS->DeclareNewWriteSRS(poSRSOri);
    1209          19 :     if (poSRSOri)
    1210             :     {
    1211           6 :         auto poSRS = poSRSOri->Clone();
    1212           6 :         poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1213           6 :         oCleanCopy.SetSpatialRef(poSRS);
    1214           6 :         poSRS->Release();
    1215             :     }
    1216          19 :     char *pszName = CPLStrdup(poField->GetNameRef());
    1217          19 :     CPLCleanXMLElementName(pszName);
    1218             : 
    1219          19 :     if (strcmp(pszName, poField->GetNameRef()) != 0)
    1220             :     {
    1221           0 :         if (!bApproxOK)
    1222             :         {
    1223           0 :             CPLFree(pszName);
    1224           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1225             :                      "Unable to create field with name '%s', it would not\n"
    1226             :                      "be valid as an XML element name.",
    1227             :                      poField->GetNameRef());
    1228           0 :             return OGRERR_FAILURE;
    1229             :         }
    1230             : 
    1231           0 :         oCleanCopy.SetName(pszName);
    1232           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1233             :                  "Field name '%s' adjusted to '%s' to be a valid\n"
    1234             :                  "XML element name.",
    1235             :                  poField->GetNameRef(), pszName);
    1236             :     }
    1237             : 
    1238          19 :     CPLFree(pszName);
    1239             : 
    1240          19 :     poFeatureDefn->AddGeomFieldDefn(&oCleanCopy);
    1241             : 
    1242          19 :     return OGRERR_NONE;
    1243             : }
    1244             : 
    1245             : /************************************************************************/
    1246             : /*                             GetDataset()                             */
    1247             : /************************************************************************/
    1248             : 
    1249          18 : GDALDataset *OGRGMLLayer::GetDataset()
    1250             : {
    1251          18 :     return poDS;
    1252             : }

Generated by: LCOV version 1.14