LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlutils - gmlfeatureclass.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 481 588 81.8 %
Date: 2025-12-13 00:55:36 Functions: 28 30 93.3 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Project:  GML Reader
       4             :  * Purpose:  Implementation of GMLFeatureClass.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  **********************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gmlfeature.h"
      16             : 
      17             : #include <cmath>
      18             : #include <cstddef>
      19             : #include <cstdio>
      20             : #include <cstdlib>
      21             : #include <cstring>
      22             : #include <limits>
      23             : #include <string>
      24             : 
      25             : #include "cpl_conv.h"
      26             : #include "cpl_error.h"
      27             : #include "cpl_minixml.h"
      28             : #include "cpl_string.h"
      29             : #include "ogr_core.h"
      30             : #include "ogr_p.h"
      31             : #include "ogr_geometry.h"
      32             : 
      33             : /************************************************************************/
      34             : /*                          GMLFeatureClass()                           */
      35             : /************************************************************************/
      36             : 
      37         915 : GMLFeatureClass::GMLFeatureClass(const char *pszName)
      38         915 :     : m_pszName(CPLStrdup(pszName)), m_pszElementName(nullptr),
      39         915 :       n_nNameLen(static_cast<int>(strlen(pszName))), n_nElementNameLen(0),
      40             :       m_nPropertyCount(0), m_papoProperty(nullptr), m_nGeometryPropertyCount(0),
      41             :       m_papoGeometryProperty(nullptr), m_bSchemaLocked(false),
      42             :       m_nFeatureCount(-1),  // Unknown.
      43             :       m_pszExtraInfo(nullptr), m_bHaveExtents(false), m_dfXMin(0.0),
      44             :       m_dfXMax(0.0), m_dfYMin(0.0), m_dfYMax(0.0), m_pszSRSName(nullptr),
      45         915 :       m_bSRSNameConsistent(true)
      46             : {
      47         915 : }
      48             : 
      49             : /************************************************************************/
      50             : /*                          ~GMLFeatureClass()                          */
      51             : /************************************************************************/
      52             : 
      53         915 : GMLFeatureClass::~GMLFeatureClass()
      54             : 
      55             : {
      56         915 :     CPLFree(m_pszName);
      57         915 :     CPLFree(m_pszElementName);
      58             : 
      59        3990 :     for (int i = 0; i < m_nPropertyCount; i++)
      60        3075 :         delete m_papoProperty[i];
      61         915 :     CPLFree(m_papoProperty);
      62             : 
      63         915 :     ClearGeometryProperties();
      64             : 
      65         915 :     CPLFree(m_pszSRSName);
      66         915 : }
      67             : 
      68             : /************************************************************************/
      69             : /*                         StealProperties()                            */
      70             : /************************************************************************/
      71             : 
      72           4 : void GMLFeatureClass::StealProperties()
      73             : {
      74           4 :     m_nPropertyCount = 0;
      75           4 :     CPLFree(m_papoProperty);
      76           4 :     m_papoProperty = nullptr;
      77           4 :     m_oMapPropertyNameToIndex.clear();
      78           4 :     m_oMapPropertySrcElementToIndex.clear();
      79           4 : }
      80             : 
      81             : /************************************************************************/
      82             : /*                       StealGeometryProperties()                      */
      83             : /************************************************************************/
      84             : 
      85           2 : void GMLFeatureClass::StealGeometryProperties()
      86             : {
      87           2 :     m_nGeometryPropertyCount = 0;
      88           2 :     CPLFree(m_papoGeometryProperty);
      89           2 :     m_papoGeometryProperty = nullptr;
      90           2 : }
      91             : 
      92             : /************************************************************************/
      93             : /*                            SetName()                                 */
      94             : /************************************************************************/
      95             : 
      96           3 : void GMLFeatureClass::SetName(const char *pszNewName)
      97             : {
      98           3 :     CPLFree(m_pszName);
      99           3 :     m_pszName = CPLStrdup(pszNewName);
     100           3 : }
     101             : 
     102             : /************************************************************************/
     103             : /*                           GetProperty(int)                           */
     104             : /************************************************************************/
     105             : 
     106       37319 : GMLPropertyDefn *GMLFeatureClass::GetProperty(int iIndex) const
     107             : 
     108             : {
     109       37319 :     if (iIndex < 0 || iIndex >= m_nPropertyCount)
     110        3599 :         return nullptr;
     111             : 
     112       33720 :     return m_papoProperty[iIndex];
     113             : }
     114             : 
     115             : /************************************************************************/
     116             : /*                          GetPropertyIndex()                          */
     117             : /************************************************************************/
     118             : 
     119        3736 : int GMLFeatureClass::GetPropertyIndex(const char *pszName) const
     120             : 
     121             : {
     122        3736 :     auto oIter = m_oMapPropertyNameToIndex.find(CPLString(pszName).toupper());
     123        3736 :     if (oIter != m_oMapPropertyNameToIndex.end())
     124          23 :         return oIter->second;
     125             : 
     126        3713 :     return -1;
     127             : }
     128             : 
     129             : /************************************************************************/
     130             : /*                        GetPropertyIndexBySrcElement()                */
     131             : /************************************************************************/
     132             : 
     133        5904 : int GMLFeatureClass::GetPropertyIndexBySrcElement(const char *pszElement,
     134             :                                                   int nLen) const
     135             : 
     136             : {
     137             :     auto oIter =
     138        5904 :         m_oMapPropertySrcElementToIndex.find(CPLString(pszElement, nLen));
     139        5904 :     if (oIter != m_oMapPropertySrcElementToIndex.end())
     140        3178 :         return oIter->second;
     141             : 
     142        2726 :     return -1;
     143             : }
     144             : 
     145             : /************************************************************************/
     146             : /*                            AddProperty()                             */
     147             : /************************************************************************/
     148             : 
     149        3095 : int GMLFeatureClass::AddProperty(GMLPropertyDefn *poDefn, int iPos)
     150             : 
     151             : {
     152        3095 :     if (GetProperty(poDefn->GetName()) != nullptr)
     153             :     {
     154           2 :         CPLError(CE_Warning, CPLE_AppDefined,
     155             :                  "Field with same name (%s) already exists in (%s). "
     156             :                  "Skipping newer ones",
     157             :                  poDefn->GetName(), m_pszName);
     158           2 :         return -1;
     159             :     }
     160             : 
     161        3093 :     m_nPropertyCount++;
     162        3093 :     m_papoProperty = static_cast<GMLPropertyDefn **>(
     163        3093 :         CPLRealloc(m_papoProperty, sizeof(void *) * m_nPropertyCount));
     164             : 
     165        3093 :     if (iPos < 0)
     166             :     {
     167        3090 :         iPos = m_nPropertyCount - 1;
     168             :     }
     169           3 :     else if (iPos < m_nPropertyCount - 1)
     170             :     {
     171           3 :         memmove(m_papoProperty + iPos + 1, m_papoProperty + iPos,
     172           3 :                 (m_nPropertyCount - 1 - iPos) * sizeof(GMLPropertyDefn *));
     173          12 :         for (auto &iter : m_oMapPropertyNameToIndex)
     174             :         {
     175           9 :             if (iter.second >= iPos)
     176           6 :                 iter.second++;
     177             :         }
     178          12 :         for (auto &iter : m_oMapPropertySrcElementToIndex)
     179             :         {
     180           9 :             if (iter.second >= iPos)
     181           6 :                 iter.second++;
     182             :         }
     183             :     }
     184             : 
     185        3093 :     m_papoProperty[iPos] = poDefn;
     186        3093 :     m_oMapPropertyNameToIndex[CPLString(poDefn->GetName()).toupper()] = iPos;
     187        3093 :     if (m_oMapPropertySrcElementToIndex.find(poDefn->GetSrcElement()) ==
     188        6186 :         m_oMapPropertySrcElementToIndex.end())
     189             :     {
     190        3091 :         m_oMapPropertySrcElementToIndex[poDefn->GetSrcElement()] = iPos;
     191             :     }
     192             : 
     193        3093 :     return iPos;
     194             : }
     195             : 
     196             : /************************************************************************/
     197             : /*                         GetGeometryProperty(int)                      */
     198             : /************************************************************************/
     199             : 
     200        3325 : GMLGeometryPropertyDefn *GMLFeatureClass::GetGeometryProperty(int iIndex) const
     201             : {
     202        3325 :     if (iIndex < 0 || iIndex >= m_nGeometryPropertyCount)
     203           0 :         return nullptr;
     204             : 
     205        3325 :     return m_papoGeometryProperty[iIndex];
     206             : }
     207             : 
     208             : /************************************************************************/
     209             : /*                   GetGeometryPropertyIndexBySrcElement()             */
     210             : /************************************************************************/
     211             : 
     212        2301 : int GMLFeatureClass::GetGeometryPropertyIndexBySrcElement(
     213             :     const char *pszElement) const
     214             : 
     215             : {
     216        2576 :     for (int i = 0; i < m_nGeometryPropertyCount; i++)
     217        1509 :         if (strcmp(pszElement, m_papoGeometryProperty[i]->GetSrcElement()) == 0)
     218        1234 :             return i;
     219             : 
     220        1067 :     return -1;
     221             : }
     222             : 
     223             : /************************************************************************/
     224             : /*                         AddGeometryProperty()                        */
     225             : /************************************************************************/
     226             : 
     227         937 : int GMLFeatureClass::AddGeometryProperty(GMLGeometryPropertyDefn *poDefn)
     228             : 
     229             : {
     230         937 :     if (GetGeometryPropertyIndexBySrcElement(poDefn->GetSrcElement()) >= 0)
     231             :     {
     232           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     233             :                  "Geometry field with same name (%s) already exists in (%s). "
     234             :                  "Skipping newer ones",
     235             :                  poDefn->GetSrcElement(), m_pszName);
     236           0 :         return -1;
     237             :     }
     238             : 
     239         937 :     m_nGeometryPropertyCount++;
     240        1874 :     m_papoGeometryProperty = static_cast<GMLGeometryPropertyDefn **>(CPLRealloc(
     241         937 :         m_papoGeometryProperty, sizeof(void *) * m_nGeometryPropertyCount));
     242             : 
     243         937 :     m_papoGeometryProperty[m_nGeometryPropertyCount - 1] = poDefn;
     244             : 
     245         937 :     return m_nGeometryPropertyCount - 1;
     246             : }
     247             : 
     248             : /************************************************************************/
     249             : /*                       ClearGeometryProperties()                      */
     250             : /************************************************************************/
     251             : 
     252         915 : void GMLFeatureClass::ClearGeometryProperties()
     253             : {
     254        1848 :     for (int i = 0; i < m_nGeometryPropertyCount; i++)
     255         933 :         delete m_papoGeometryProperty[i];
     256         915 :     CPLFree(m_papoGeometryProperty);
     257         915 :     m_nGeometryPropertyCount = 0;
     258         915 :     m_papoGeometryProperty = nullptr;
     259         915 : }
     260             : 
     261             : /************************************************************************/
     262             : /*                         HasFeatureProperties()                       */
     263             : /************************************************************************/
     264             : 
     265        1096 : bool GMLFeatureClass::HasFeatureProperties()
     266             : {
     267        4052 :     for (int i = 0; i < m_nPropertyCount; i++)
     268             :     {
     269        5926 :         if (m_papoProperty[i]->GetType() == GMLPT_FeatureProperty ||
     270        2961 :             m_papoProperty[i]->GetType() == GMLPT_FeaturePropertyList)
     271           9 :             return true;
     272             :     }
     273        1087 :     return false;
     274             : }
     275             : 
     276             : /************************************************************************/
     277             : /*                           SetElementName()                           */
     278             : /************************************************************************/
     279             : 
     280         160 : void GMLFeatureClass::SetElementName(const char *pszElementName)
     281             : 
     282             : {
     283         160 :     CPLFree(m_pszElementName);
     284         160 :     m_pszElementName = CPLStrdup(pszElementName);
     285         160 :     n_nElementNameLen = static_cast<int>(strlen(pszElementName));
     286         160 : }
     287             : 
     288             : /************************************************************************/
     289             : /*                           GetElementName()                           */
     290             : /************************************************************************/
     291             : 
     292        7979 : const char *GMLFeatureClass::GetElementName() const
     293             : 
     294             : {
     295        7979 :     if (m_pszElementName == nullptr)
     296        6067 :         return m_pszName;
     297             : 
     298        1912 :     return m_pszElementName;
     299             : }
     300             : 
     301             : /************************************************************************/
     302             : /*                           GetElementName()                           */
     303             : /************************************************************************/
     304             : 
     305       26566 : size_t GMLFeatureClass::GetElementNameLen() const
     306             : 
     307             : {
     308       26566 :     if (m_pszElementName == nullptr)
     309       11348 :         return n_nNameLen;
     310             : 
     311       15218 :     return n_nElementNameLen;
     312             : }
     313             : 
     314             : /************************************************************************/
     315             : /*                         GetFeatureCount()                          */
     316             : /************************************************************************/
     317             : 
     318        2032 : GIntBig GMLFeatureClass::GetFeatureCount()
     319             : {
     320        2032 :     return m_nFeatureCount;
     321             : }
     322             : 
     323             : /************************************************************************/
     324             : /*                          SetFeatureCount()                           */
     325             : /************************************************************************/
     326             : 
     327         971 : void GMLFeatureClass::SetFeatureCount(GIntBig nNewCount)
     328             : 
     329             : {
     330         971 :     m_nFeatureCount = nNewCount;
     331         971 : }
     332             : 
     333             : /************************************************************************/
     334             : /*                            GetExtraInfo()                            */
     335             : /************************************************************************/
     336             : 
     337           0 : const char *GMLFeatureClass::GetExtraInfo()
     338             : {
     339           0 :     return m_pszExtraInfo;
     340             : }
     341             : 
     342             : /************************************************************************/
     343             : /*                            SetExtraInfo()                            */
     344             : /************************************************************************/
     345             : 
     346           0 : void GMLFeatureClass::SetExtraInfo(const char *pszExtraInfo)
     347             : 
     348             : {
     349           0 :     CPLFree(m_pszExtraInfo);
     350           0 :     m_pszExtraInfo = nullptr;
     351             : 
     352           0 :     if (pszExtraInfo != nullptr)
     353           0 :         m_pszExtraInfo = CPLStrdup(pszExtraInfo);
     354           0 : }
     355             : 
     356             : /************************************************************************/
     357             : /*                             SetExtents()                             */
     358             : /************************************************************************/
     359             : 
     360         779 : void GMLFeatureClass::SetExtents(double dfXMin, double dfXMax, double dfYMin,
     361             :                                  double dfYMax)
     362             : 
     363             : {
     364         779 :     m_dfXMin = dfXMin;
     365         779 :     m_dfXMax = dfXMax;
     366         779 :     m_dfYMin = dfYMin;
     367         779 :     m_dfYMax = dfYMax;
     368             : 
     369         779 :     m_bHaveExtents = true;
     370         779 : }
     371             : 
     372             : /************************************************************************/
     373             : /*                             GetExtents()                             */
     374             : /************************************************************************/
     375             : 
     376         704 : bool GMLFeatureClass::GetExtents(double *pdfXMin, double *pdfXMax,
     377             :                                  double *pdfYMin, double *pdfYMax)
     378             : 
     379             : {
     380         704 :     if (m_bHaveExtents)
     381             :     {
     382         573 :         *pdfXMin = m_dfXMin;
     383         573 :         *pdfXMax = m_dfXMax;
     384         573 :         *pdfYMin = m_dfYMin;
     385         573 :         *pdfYMax = m_dfYMax;
     386             :     }
     387             : 
     388         704 :     return m_bHaveExtents;
     389             : }
     390             : 
     391             : /************************************************************************/
     392             : /*                            SetSRSName()                              */
     393             : /************************************************************************/
     394             : 
     395         170 : void GMLFeatureClass::SetSRSName(const char *pszSRSName)
     396             : 
     397             : {
     398         170 :     m_bSRSNameConsistent = true;
     399         170 :     CPLFree(m_pszSRSName);
     400         170 :     m_pszSRSName = pszSRSName ? CPLStrdup(pszSRSName) : nullptr;
     401         170 : }
     402             : 
     403             : /************************************************************************/
     404             : /*                           MergeSRSName()                             */
     405             : /************************************************************************/
     406             : 
     407         240 : void GMLFeatureClass::MergeSRSName(const char *pszSRSName)
     408             : 
     409             : {
     410         240 :     if (!m_bSRSNameConsistent)
     411           0 :         return;
     412             : 
     413         240 :     if (m_pszSRSName == nullptr)
     414             :     {
     415         136 :         if (pszSRSName)
     416          36 :             m_pszSRSName = CPLStrdup(pszSRSName);
     417             :     }
     418             :     else
     419             :     {
     420         104 :         m_bSRSNameConsistent =
     421         104 :             pszSRSName != nullptr && strcmp(m_pszSRSName, pszSRSName) == 0;
     422         104 :         if (!m_bSRSNameConsistent)
     423             :         {
     424           1 :             CPLFree(m_pszSRSName);
     425           1 :             m_pszSRSName = nullptr;
     426             :         }
     427             :     }
     428             : }
     429             : 
     430             : /************************************************************************/
     431             : /*                         InitializeFromXML()                          */
     432             : /************************************************************************/
     433             : 
     434         111 : bool GMLFeatureClass::InitializeFromXML(CPLXMLNode *psRoot)
     435             : 
     436             : {
     437             :     // Do some rudimentary checking that this is a well formed node.
     438         111 :     if (psRoot == nullptr || psRoot->eType != CXT_Element ||
     439         111 :         !EQUAL(psRoot->pszValue, "GMLFeatureClass"))
     440             :     {
     441           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     442             :                  "GMLFeatureClass::InitializeFromXML() called on %s node!",
     443             :                  psRoot ? psRoot->pszValue : "(null)");
     444           0 :         return false;
     445             :     }
     446             : 
     447         111 :     if (CPLGetXMLValue(psRoot, "Name", nullptr) == nullptr)
     448             :     {
     449           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     450             :                  "GMLFeatureClass has no <Name> element.");
     451           0 :         return false;
     452             :     }
     453             : 
     454             :     // Collect base info.
     455         111 :     CPLFree(m_pszName);
     456         111 :     m_pszName = CPLStrdup(CPLGetXMLValue(psRoot, "Name", nullptr));
     457         111 :     n_nNameLen = static_cast<int>(strlen(m_pszName));
     458             : 
     459         111 :     SetElementName(CPLGetXMLValue(psRoot, "ElementPath", m_pszName));
     460             : 
     461             :     // Collect geometry properties.
     462         111 :     bool bHasValidGeometryName = false;
     463         111 :     bool bHasValidGeometryElementPath = false;
     464         111 :     bool bHasFoundGeomType = false;
     465         111 :     bool bHasFoundGeomElements = false;
     466         111 :     const char *pszGName = "";
     467         111 :     const char *pszGPath = "";
     468         111 :     OGRwkbGeometryType nGeomType = wkbUnknown;
     469             : 
     470         136 :     const auto FlattenGeomTypeFromInt = [](int eType)
     471             :     {
     472         136 :         eType = eType & (~wkb25DBitInternalUse);
     473         136 :         if (eType >= 1000 && eType < 2000)  // ISO Z.
     474           0 :             return eType - 1000;
     475         136 :         if (eType >= 2000 && eType < 3000)  // ISO M.
     476           0 :             return eType - 2000;
     477         136 :         if (eType >= 3000 && eType < 4000)  // ISO ZM.
     478           0 :             return eType - 3000;
     479         136 :         return eType;
     480             :     };
     481             : 
     482         111 :     CPLXMLNode *psThis = nullptr;
     483        1708 :     for (psThis = psRoot->psChild; psThis != nullptr; psThis = psThis->psNext)
     484             :     {
     485        1609 :         if (psThis->eType == CXT_Element &&
     486        1179 :             EQUAL(psThis->pszValue, "GeomPropertyDefn"))
     487             :         {
     488          79 :             const char *pszName = CPLGetXMLValue(psThis, "Name", "");
     489             :             const char *pszElementPath =
     490          79 :                 CPLGetXMLValue(psThis, "ElementPath", "");
     491          79 :             const char *pszType = CPLGetXMLValue(psThis, "Type", nullptr);
     492             :             const bool bNullable =
     493          79 :                 CPLTestBool(CPLGetXMLValue(psThis, "Nullable", "true"));
     494          79 :             nGeomType = wkbUnknown;
     495          79 :             if (pszType != nullptr && !EQUAL(pszType, "0"))
     496             :             {
     497          77 :                 int nGeomTypeInt = atoi(pszType);
     498             :                 const int nFlattenGeomTypeInt =
     499          77 :                     FlattenGeomTypeFromInt(nGeomTypeInt);
     500          77 :                 if (nGeomTypeInt != 0 &&
     501           6 :                     !(nFlattenGeomTypeInt >= static_cast<int>(wkbPoint) &&
     502             :                       nFlattenGeomTypeInt <= static_cast<int>(wkbTIN)))
     503             :                 {
     504           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     505             :                              "Unrecognized geometry type : %s", pszType);
     506             :                 }
     507          77 :                 else if (nGeomTypeInt == 0)
     508             :                 {
     509          71 :                     nGeomType = OGRFromOGCGeomType(pszType);
     510             :                 }
     511             :                 else
     512             :                 {
     513           6 :                     nGeomType = static_cast<OGRwkbGeometryType>(nGeomTypeInt);
     514             :                 }
     515             :             }
     516          79 :             bHasFoundGeomElements = true;
     517             :             auto poDefn = new GMLGeometryPropertyDefn(pszName, pszElementPath,
     518          79 :                                                       nGeomType, -1, bNullable);
     519          79 :             if (AddGeometryProperty(poDefn) < 0)
     520           0 :                 delete poDefn;
     521          79 :             bHasValidGeometryName = false;
     522          79 :             bHasValidGeometryElementPath = false;
     523          79 :             bHasFoundGeomType = false;
     524             :         }
     525        1530 :         else if (psThis->eType == CXT_Element &&
     526        1100 :                  strcmp(psThis->pszValue, "GeometryName") == 0)
     527             :         {
     528          41 :             bHasFoundGeomElements = true;
     529             : 
     530          41 :             if (bHasValidGeometryName)
     531             :             {
     532             :                 auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath,
     533           0 :                                                           nGeomType, -1, true);
     534           0 :                 if (AddGeometryProperty(poDefn) < 0)
     535           0 :                     delete poDefn;
     536             :                 // bHasValidGeometryName = false;
     537           0 :                 bHasValidGeometryElementPath = false;
     538           0 :                 bHasFoundGeomType = false;
     539           0 :                 pszGPath = "";
     540           0 :                 nGeomType = wkbUnknown;
     541             :             }
     542          41 :             pszGName = CPLGetXMLValue(psThis, nullptr, "");
     543          41 :             bHasValidGeometryName = true;
     544             :         }
     545        1489 :         else if (psThis->eType == CXT_Element &&
     546        1059 :                  strcmp(psThis->pszValue, "GeometryElementPath") == 0)
     547             :         {
     548          48 :             bHasFoundGeomElements = true;
     549             : 
     550          48 :             if (bHasValidGeometryElementPath)
     551             :             {
     552             :                 auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath,
     553           0 :                                                           nGeomType, -1, true);
     554           0 :                 if (AddGeometryProperty(poDefn) < 0)
     555           0 :                     delete poDefn;
     556           0 :                 bHasValidGeometryName = false;
     557             :                 // bHasValidGeometryElementPath = false;
     558           0 :                 bHasFoundGeomType = false;
     559           0 :                 pszGName = "";
     560           0 :                 nGeomType = wkbUnknown;
     561             :             }
     562          48 :             pszGPath = CPLGetXMLValue(psThis, nullptr, "");
     563          48 :             bHasValidGeometryElementPath = true;
     564             :         }
     565        1441 :         else if (psThis->eType == CXT_Element &&
     566        1011 :                  strcmp(psThis->pszValue, "GeometryType") == 0)
     567             :         {
     568          59 :             bHasFoundGeomElements = true;
     569             : 
     570          59 :             if (bHasFoundGeomType)
     571             :             {
     572             :                 auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath,
     573           0 :                                                           nGeomType, -1, true);
     574           0 :                 if (AddGeometryProperty(poDefn) < 0)
     575           0 :                     delete poDefn;
     576           0 :                 bHasValidGeometryName = false;
     577           0 :                 bHasValidGeometryElementPath = false;
     578             :                 // bHasFoundGeomType = false;
     579           0 :                 pszGName = "";
     580           0 :                 pszGPath = "";
     581             :             }
     582             :             const char *pszGeometryType =
     583          59 :                 CPLGetXMLValue(psThis, nullptr, nullptr);
     584          59 :             nGeomType = wkbUnknown;
     585          59 :             if (pszGeometryType != nullptr && !EQUAL(pszGeometryType, "0"))
     586             :             {
     587          59 :                 const int nGeomTypeInt = atoi(pszGeometryType);
     588             :                 const int nFlattenGeomTypeInt =
     589          59 :                     FlattenGeomTypeFromInt(nGeomTypeInt);
     590          59 :                 if (nGeomTypeInt == 100 || EQUAL(pszGeometryType, "NONE"))
     591             :                 {
     592          12 :                     bHasValidGeometryElementPath = false;
     593          12 :                     bHasFoundGeomType = false;
     594          12 :                     break;
     595             :                 }
     596          47 :                 else if (nGeomTypeInt != 0 &&
     597          42 :                          !(nFlattenGeomTypeInt >= static_cast<int>(wkbPoint) &&
     598             :                            nFlattenGeomTypeInt <= static_cast<int>(wkbTIN)))
     599             :                 {
     600           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     601             :                              "Unrecognized geometry type : %s",
     602             :                              pszGeometryType);
     603             :                 }
     604          47 :                 else if (nGeomTypeInt == 0)
     605             :                 {
     606           5 :                     nGeomType = OGRFromOGCGeomType(pszGeometryType);
     607             :                 }
     608             :                 else
     609             :                 {
     610          42 :                     nGeomType = static_cast<OGRwkbGeometryType>(nGeomTypeInt);
     611             :                 }
     612             :             }
     613          47 :             bHasFoundGeomType = true;
     614             :         }
     615             :     }
     616             : 
     617             :     // If there was a dangling <GeometryElementPath> or <GeometryType> or
     618             :     // that no explicit geometry information has been found, then add
     619             :     // a geometry field.
     620         111 :     if (bHasValidGeometryElementPath || bHasFoundGeomType ||
     621          61 :         !bHasFoundGeomElements)
     622             :     {
     623             :         auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath, nGeomType,
     624          65 :                                                   -1, true);
     625          65 :         if (AddGeometryProperty(poDefn) < 0)
     626           0 :             delete poDefn;
     627             :     }
     628             : 
     629         111 :     SetSRSName(CPLGetXMLValue(psRoot, "SRSName", nullptr));
     630             : 
     631             :     // Collect dataset specific info.
     632         111 :     CPLXMLNode *psDSI = CPLGetXMLNode(psRoot, "DatasetSpecificInfo");
     633         111 :     if (psDSI != nullptr)
     634             :     {
     635          63 :         const char *pszValue = CPLGetXMLValue(psDSI, "FeatureCount", nullptr);
     636          63 :         if (pszValue != nullptr)
     637             :         {
     638          63 :             const auto nValue = CPLAtoGIntBig(pszValue);
     639             :             // size of "<fMember><x/></fMember>"
     640          63 :             constexpr int MIN_SIZE_FEATURE = 23;
     641         126 :             if (nValue >= 0 &&
     642          63 :                 nValue < std::numeric_limits<int64_t>::max() / MIN_SIZE_FEATURE)
     643             :             {
     644          63 :                 SetFeatureCount(nValue);
     645             :             }
     646             :         }
     647             : 
     648             :         // Eventually we should support XML subtrees.
     649          63 :         pszValue = CPLGetXMLValue(psDSI, "ExtraInfo", nullptr);
     650          63 :         if (pszValue != nullptr)
     651           0 :             SetExtraInfo(pszValue);
     652             : 
     653          63 :         if (CPLGetXMLValue(psDSI, "ExtentXMin", nullptr) != nullptr &&
     654          54 :             CPLGetXMLValue(psDSI, "ExtentXMax", nullptr) != nullptr &&
     655         171 :             CPLGetXMLValue(psDSI, "ExtentYMin", nullptr) != nullptr &&
     656          54 :             CPLGetXMLValue(psDSI, "ExtentYMax", nullptr) != nullptr)
     657             :         {
     658          54 :             SetExtents(CPLAtof(CPLGetXMLValue(psDSI, "ExtentXMin", "0.0")),
     659             :                        CPLAtof(CPLGetXMLValue(psDSI, "ExtentXMax", "0.0")),
     660             :                        CPLAtof(CPLGetXMLValue(psDSI, "ExtentYMin", "0.0")),
     661             :                        CPLAtof(CPLGetXMLValue(psDSI, "ExtentYMax", "0.0")));
     662             :         }
     663             :     }
     664             : 
     665             :     // Collect property definitions.
     666        1768 :     for (psThis = psRoot->psChild; psThis != nullptr; psThis = psThis->psNext)
     667             :     {
     668        1657 :         if (psThis->eType == CXT_Element &&
     669        1227 :             EQUAL(psThis->pszValue, "PropertyDefn"))
     670             :         {
     671         660 :             const char *pszName = CPLGetXMLValue(psThis, "Name", nullptr);
     672         660 :             const char *pszType = CPLGetXMLValue(psThis, "Type", "Untyped");
     673         660 :             const char *pszSubType = CPLGetXMLValue(psThis, "Subtype", "");
     674             :             const char *pszCondition =
     675         660 :                 CPLGetXMLValue(psThis, "Condition", nullptr);
     676             :             const bool bNullable =
     677         660 :                 CPLTestBool(CPLGetXMLValue(psThis, "Nullable", "true"));
     678             :             const bool bUnique =
     679         660 :                 CPLTestBool(CPLGetXMLValue(psThis, "Unique", "false"));
     680         660 :             const char *pszComment = CPLGetXMLValue(psThis, "Comment", nullptr);
     681             : 
     682         660 :             if (pszName == nullptr)
     683             :             {
     684           0 :                 CPLError(
     685             :                     CE_Failure, CPLE_AppDefined,
     686             :                     "GMLFeatureClass %s has a PropertyDefn without a <Name>.",
     687             :                     m_pszName);
     688           0 :                 return false;
     689             :             }
     690             : 
     691             :             GMLPropertyDefn *poPDefn = new GMLPropertyDefn(
     692         660 :                 pszName, CPLGetXMLValue(psThis, "ElementPath", nullptr));
     693             : 
     694         660 :             poPDefn->SetNullable(bNullable);
     695         660 :             poPDefn->SetUnique(bUnique);
     696         660 :             if (EQUAL(pszType, "Untyped"))
     697             :             {
     698           0 :                 poPDefn->SetType(GMLPT_Untyped);
     699             :             }
     700         660 :             else if (EQUAL(pszType, "String"))
     701             :             {
     702         364 :                 if (EQUAL(pszSubType, "Boolean"))
     703             :                 {
     704           4 :                     poPDefn->SetType(GMLPT_Boolean);
     705           4 :                     poPDefn->SetWidth(1);
     706             :                 }
     707         360 :                 else if (EQUAL(pszSubType, "Date"))
     708             :                 {
     709           2 :                     poPDefn->SetType(GMLPT_Date);
     710             :                 }
     711         358 :                 else if (EQUAL(pszSubType, "Time"))
     712             :                 {
     713           0 :                     poPDefn->SetType(GMLPT_Time);
     714             :                 }
     715         358 :                 else if (EQUAL(pszSubType, "Datetime"))
     716             :                 {
     717           0 :                     poPDefn->SetType(GMLPT_DateTime);
     718             :                 }
     719             :                 else
     720             :                 {
     721         358 :                     poPDefn->SetType(GMLPT_String);
     722         358 :                     poPDefn->SetWidth(
     723             :                         atoi(CPLGetXMLValue(psThis, "Width", "0")));
     724             :                 }
     725             :             }
     726         296 :             else if (EQUAL(pszType, "Integer"))
     727             :             {
     728         195 :                 if (EQUAL(pszSubType, "Short"))
     729             :                 {
     730           0 :                     poPDefn->SetType(GMLPT_Short);
     731             :                 }
     732         195 :                 else if (EQUAL(pszSubType, "Integer64"))
     733             :                 {
     734          60 :                     poPDefn->SetType(GMLPT_Integer64);
     735             :                 }
     736             :                 else
     737             :                 {
     738         135 :                     poPDefn->SetType(GMLPT_Integer);
     739             :                 }
     740         195 :                 poPDefn->SetWidth(atoi(CPLGetXMLValue(psThis, "Width", "0")));
     741             :             }
     742         101 :             else if (EQUAL(pszType, "Real"))
     743             :             {
     744          12 :                 if (EQUAL(pszSubType, "Float"))
     745             :                 {
     746           0 :                     poPDefn->SetType(GMLPT_Float);
     747             :                 }
     748             :                 else
     749             :                 {
     750          12 :                     poPDefn->SetType(GMLPT_Real);
     751             :                 }
     752          12 :                 poPDefn->SetWidth(atoi(CPLGetXMLValue(psThis, "Width", "0")));
     753          12 :                 poPDefn->SetPrecision(
     754             :                     atoi(CPLGetXMLValue(psThis, "Precision", "0")));
     755             :             }
     756          89 :             else if (EQUAL(pszType, "StringList"))
     757             :             {
     758          33 :                 if (EQUAL(pszSubType, "Boolean"))
     759           1 :                     poPDefn->SetType(GMLPT_BooleanList);
     760             :                 else
     761          32 :                     poPDefn->SetType(GMLPT_StringList);
     762             :             }
     763          56 :             else if (EQUAL(pszType, "IntegerList"))
     764             :             {
     765          27 :                 if (EQUAL(pszSubType, "Integer64"))
     766           6 :                     poPDefn->SetType(GMLPT_Integer64List);
     767             :                 else
     768          21 :                     poPDefn->SetType(GMLPT_IntegerList);
     769             :             }
     770          29 :             else if (EQUAL(pszType, "RealList"))
     771             :             {
     772          11 :                 poPDefn->SetType(GMLPT_RealList);
     773             :             }
     774          18 :             else if (EQUAL(pszType, "Complex"))
     775             :             {
     776           8 :                 poPDefn->SetType(GMLPT_Complex);
     777             :             }
     778          10 :             else if (EQUAL(pszType, "FeatureProperty"))
     779             :             {
     780           2 :                 poPDefn->SetType(GMLPT_FeatureProperty);
     781             :             }
     782           8 :             else if (EQUAL(pszType, "FeaturePropertyList"))
     783             :             {
     784           8 :                 poPDefn->SetType(GMLPT_FeaturePropertyList);
     785             :             }
     786             :             else
     787             :             {
     788           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     789             :                          "Unrecognized property type (%s) in (%s).", pszType,
     790             :                          pszName);
     791           0 :                 delete poPDefn;
     792           0 :                 return false;
     793             :             }
     794         660 :             if (pszCondition != nullptr)
     795           4 :                 poPDefn->SetCondition(pszCondition);
     796         660 :             if (pszComment != nullptr)
     797           1 :                 poPDefn->SetDocumentation(pszComment);
     798             : 
     799         660 :             if (AddProperty(poPDefn) < 0)
     800           0 :                 delete poPDefn;
     801             :         }
     802             :     }
     803             : 
     804         111 :     return true;
     805             : }
     806             : 
     807             : /************************************************************************/
     808             : /*                           SerializeToXML()                           */
     809             : /************************************************************************/
     810             : 
     811         141 : CPLXMLNode *GMLFeatureClass::SerializeToXML()
     812             : 
     813             : {
     814             :     // Set feature class and core information.
     815             :     CPLXMLNode *psRoot =
     816         141 :         CPLCreateXMLNode(nullptr, CXT_Element, "GMLFeatureClass");
     817             : 
     818         141 :     CPLCreateXMLElementAndValue(psRoot, "Name", GetName());
     819         141 :     CPLCreateXMLElementAndValue(psRoot, "ElementPath", GetElementName());
     820             : 
     821         141 :     if (m_nGeometryPropertyCount > 1)
     822             :     {
     823           6 :         for (int i = 0; i < m_nGeometryPropertyCount; i++)
     824             :         {
     825           4 :             GMLGeometryPropertyDefn *poGeomFDefn = m_papoGeometryProperty[i];
     826             : 
     827             :             CPLXMLNode *psPDefnNode =
     828           4 :                 CPLCreateXMLNode(psRoot, CXT_Element, "GeomPropertyDefn");
     829           4 :             if (strlen(poGeomFDefn->GetName()) > 0)
     830           4 :                 CPLCreateXMLElementAndValue(psPDefnNode, "Name",
     831             :                                             poGeomFDefn->GetName());
     832           8 :             if (poGeomFDefn->GetSrcElement() != nullptr &&
     833           4 :                 strlen(poGeomFDefn->GetSrcElement()) > 0)
     834           4 :                 CPLCreateXMLElementAndValue(psPDefnNode, "ElementPath",
     835             :                                             poGeomFDefn->GetSrcElement());
     836             : 
     837           4 :             if (poGeomFDefn->GetType() != 0 /* wkbUnknown */)
     838             :             {
     839           0 :                 char szValue[128] = {};
     840             : 
     841             :                 const OGRwkbGeometryType eType =
     842           0 :                     static_cast<OGRwkbGeometryType>(poGeomFDefn->GetType());
     843             : 
     844           0 :                 CPLString osStr(OGRToOGCGeomType(eType));
     845           0 :                 if (wkbHasZ(eType))
     846           0 :                     osStr += "Z";
     847           0 :                 CPLCreateXMLNode(psPDefnNode, CXT_Comment, osStr.c_str());
     848             : 
     849           0 :                 snprintf(szValue, sizeof(szValue), "%d", eType);
     850           0 :                 CPLCreateXMLElementAndValue(psPDefnNode, "Type", szValue);
     851             :             }
     852             :         }
     853             :     }
     854         139 :     else if (m_nGeometryPropertyCount == 1)
     855             :     {
     856         114 :         GMLGeometryPropertyDefn *poGeomFDefn = m_papoGeometryProperty[0];
     857             : 
     858         114 :         if (strlen(poGeomFDefn->GetName()) > 0)
     859          86 :             CPLCreateXMLElementAndValue(psRoot, "GeometryName",
     860             :                                         poGeomFDefn->GetName());
     861             : 
     862         228 :         if (poGeomFDefn->GetSrcElement() != nullptr &&
     863         114 :             strlen(poGeomFDefn->GetSrcElement()) > 0)
     864          86 :             CPLCreateXMLElementAndValue(psRoot, "GeometryElementPath",
     865             :                                         poGeomFDefn->GetSrcElement());
     866             : 
     867         114 :         if (poGeomFDefn->GetType() != 0 /* wkbUnknown */)
     868             :         {
     869         104 :             char szValue[128] = {};
     870             : 
     871             :             OGRwkbGeometryType eType =
     872         104 :                 static_cast<OGRwkbGeometryType>(poGeomFDefn->GetType());
     873             : 
     874         208 :             CPLString osStr(OGRToOGCGeomType(eType));
     875         104 :             if (wkbHasZ(eType))
     876           9 :                 osStr += "Z";
     877         104 :             CPLCreateXMLNode(psRoot, CXT_Comment, osStr.c_str());
     878             : 
     879         104 :             snprintf(szValue, sizeof(szValue), "%d", eType);
     880         104 :             CPLCreateXMLElementAndValue(psRoot, "GeometryType", szValue);
     881             :         }
     882             :     }
     883             :     else
     884             :     {
     885          25 :         CPLCreateXMLElementAndValue(psRoot, "GeometryType", "100");
     886             :     }
     887             : 
     888         141 :     const char *pszSRSName = GetSRSName();
     889         141 :     if (pszSRSName)
     890             :     {
     891          69 :         CPLCreateXMLElementAndValue(psRoot, "SRSName", pszSRSName);
     892             :     }
     893             : 
     894             :     // Write out dataset specific information.
     895         141 :     if (m_bHaveExtents || m_nFeatureCount != -1 || m_pszExtraInfo != nullptr)
     896             :     {
     897             :         CPLXMLNode *psDSI =
     898         140 :             CPLCreateXMLNode(psRoot, CXT_Element, "DatasetSpecificInfo");
     899             : 
     900         140 :         if (m_nFeatureCount != -1)
     901             :         {
     902         140 :             char szValue[128] = {};
     903             : 
     904         140 :             snprintf(szValue, sizeof(szValue), CPL_FRMT_GIB, m_nFeatureCount);
     905         140 :             CPLCreateXMLElementAndValue(psDSI, "FeatureCount", szValue);
     906             :         }
     907             : 
     908         140 :         if (m_bHaveExtents && fabs(m_dfXMin) < 1e100 &&
     909         112 :             fabs(m_dfXMax) < 1e100 && fabs(m_dfYMin) < 1e100 &&
     910         112 :             fabs(m_dfYMax) < 1e100)
     911             :         {
     912         112 :             char szValue[128] = {};
     913             : 
     914         112 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfXMin);
     915         112 :             CPLCreateXMLElementAndValue(psDSI, "ExtentXMin", szValue);
     916             : 
     917         112 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfXMax);
     918         112 :             CPLCreateXMLElementAndValue(psDSI, "ExtentXMax", szValue);
     919             : 
     920         112 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfYMin);
     921         112 :             CPLCreateXMLElementAndValue(psDSI, "ExtentYMin", szValue);
     922             : 
     923         112 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfYMax);
     924         112 :             CPLCreateXMLElementAndValue(psDSI, "ExtentYMax", szValue);
     925             :         }
     926             : 
     927         140 :         if (m_pszExtraInfo)
     928           0 :             CPLCreateXMLElementAndValue(psDSI, "ExtraInfo", m_pszExtraInfo);
     929             :     }
     930             : 
     931         141 :     CPLXMLNode *psLastChild = psRoot->psChild;
     932         900 :     while (psLastChild->psNext)
     933             :     {
     934         759 :         psLastChild = psLastChild->psNext;
     935             :     }
     936             : 
     937             :     // Emit property information.
     938         644 :     for (int iProperty = 0; iProperty < GetPropertyCount(); iProperty++)
     939             :     {
     940         503 :         GMLPropertyDefn *poPDefn = GetProperty(iProperty);
     941         503 :         const char *pszTypeName = "Unknown";
     942         503 :         CPL_IGNORE_RET_VAL(pszTypeName);  // Make CSA happy
     943             : 
     944             :         CPLXMLNode *psPDefnNode =
     945         503 :             CPLCreateXMLNode(nullptr, CXT_Element, "PropertyDefn");
     946         503 :         psLastChild->psNext = psPDefnNode;
     947         503 :         psLastChild = psPDefnNode;
     948         503 :         CPLCreateXMLElementAndValue(psPDefnNode, "Name", poPDefn->GetName());
     949         503 :         CPLCreateXMLElementAndValue(psPDefnNode, "ElementPath",
     950             :                                     poPDefn->GetSrcElement());
     951         503 :         const auto gmlType = poPDefn->GetType();
     952         503 :         const char *pszSubTypeName = nullptr;
     953         503 :         switch (gmlType)
     954             :         {
     955          10 :             case GMLPT_Untyped:
     956          10 :                 pszTypeName = "Untyped";
     957          10 :                 break;
     958             : 
     959         264 :             case GMLPT_String:
     960         264 :                 pszTypeName = "String";
     961         264 :                 break;
     962             : 
     963          10 :             case GMLPT_Boolean:
     964          10 :                 pszTypeName = "String";
     965          10 :                 pszSubTypeName = "Boolean";
     966          10 :                 break;
     967             : 
     968          25 :             case GMLPT_Date:
     969          25 :                 pszTypeName = "String";
     970          25 :                 pszSubTypeName = "Date";
     971          25 :                 break;
     972             : 
     973           1 :             case GMLPT_Time:
     974           1 :                 pszTypeName = "String";
     975           1 :                 pszSubTypeName = "Time";
     976           1 :                 break;
     977             : 
     978          14 :             case GMLPT_DateTime:
     979          14 :                 pszTypeName = "String";
     980          14 :                 pszSubTypeName = "DateTime";
     981          14 :                 break;
     982             : 
     983          98 :             case GMLPT_Integer:
     984          98 :                 pszTypeName = "Integer";
     985          98 :                 break;
     986             : 
     987           0 :             case GMLPT_Short:
     988           0 :                 pszTypeName = "Integer";
     989           0 :                 pszSubTypeName = "Short";
     990           0 :                 break;
     991             : 
     992           1 :             case GMLPT_Integer64:
     993           1 :                 pszTypeName = "Integer";
     994           1 :                 pszSubTypeName = "Integer64";
     995           1 :                 break;
     996             : 
     997          35 :             case GMLPT_Real:
     998          35 :                 pszTypeName = "Real";
     999          35 :                 break;
    1000             : 
    1001           0 :             case GMLPT_Float:
    1002           0 :                 pszTypeName = "Real";
    1003           0 :                 pszSubTypeName = "Float";
    1004           0 :                 break;
    1005             : 
    1006           0 :             case GMLPT_Complex:
    1007           0 :                 pszTypeName = "Complex";
    1008           0 :                 break;
    1009             : 
    1010           2 :             case GMLPT_IntegerList:
    1011           2 :                 pszTypeName = "IntegerList";
    1012           2 :                 break;
    1013             : 
    1014           1 :             case GMLPT_Integer64List:
    1015           1 :                 pszTypeName = "IntegerList";
    1016           1 :                 pszSubTypeName = "Integer64";
    1017           1 :                 break;
    1018             : 
    1019           2 :             case GMLPT_RealList:
    1020           2 :                 pszTypeName = "RealList";
    1021           2 :                 break;
    1022             : 
    1023          39 :             case GMLPT_StringList:
    1024          39 :                 pszTypeName = "StringList";
    1025          39 :                 break;
    1026             : 
    1027           1 :             case GMLPT_BooleanList:
    1028           1 :                 pszTypeName = "StringList";
    1029           1 :                 pszSubTypeName = "Boolean";
    1030           1 :                 break;
    1031             : 
    1032             :             // Should not happen in practice for now because this is not
    1033             :             // autodetected.
    1034           0 :             case GMLPT_FeatureProperty:
    1035           0 :                 pszTypeName = "FeatureProperty";
    1036           0 :                 break;
    1037             : 
    1038             :             // Should not happen in practice for now because this is not
    1039             :             // autodetected.
    1040           0 :             case GMLPT_FeaturePropertyList:
    1041           0 :                 pszTypeName = "FeaturePropertyList";
    1042           0 :                 break;
    1043             :         }
    1044         503 :         CPLCreateXMLElementAndValue(psPDefnNode, "Type", pszTypeName);
    1045         503 :         if (pszSubTypeName)
    1046          53 :             CPLCreateXMLElementAndValue(psPDefnNode, "Subtype", pszSubTypeName);
    1047             : 
    1048         503 :         if (EQUAL(pszTypeName, "String"))
    1049             :         {
    1050         314 :             char szMaxLength[48] = {};
    1051         314 :             snprintf(szMaxLength, sizeof(szMaxLength), "%d",
    1052             :                      poPDefn->GetWidth());
    1053         314 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szMaxLength);
    1054             :         }
    1055         503 :         if (poPDefn->GetWidth() > 0 && EQUAL(pszTypeName, "Integer"))
    1056             :         {
    1057           0 :             char szLength[48] = {};
    1058           0 :             snprintf(szLength, sizeof(szLength), "%d", poPDefn->GetWidth());
    1059           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szLength);
    1060             :         }
    1061         503 :         if (poPDefn->GetWidth() > 0 && EQUAL(pszTypeName, "Real"))
    1062             :         {
    1063           0 :             char szLength[48] = {};
    1064           0 :             snprintf(szLength, sizeof(szLength), "%d", poPDefn->GetWidth());
    1065           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szLength);
    1066           0 :             char szPrecision[48] = {};
    1067           0 :             snprintf(szPrecision, sizeof(szPrecision), "%d",
    1068             :                      poPDefn->GetPrecision());
    1069           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Precision", szPrecision);
    1070             :         }
    1071         503 :         if (!poPDefn->GetDocumentation().empty())
    1072             :         {
    1073           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Comment",
    1074           0 :                                         poPDefn->GetDocumentation().c_str());
    1075             :         }
    1076             :     }
    1077             : 
    1078         141 :     return psRoot;
    1079             : }
    1080             : 
    1081             : /************************************************************************/
    1082             : /*                       GML_GetOGRFieldType()                          */
    1083             : /************************************************************************/
    1084             : 
    1085        2775 : OGRFieldType GML_GetOGRFieldType(GMLPropertyType eType,
    1086             :                                  OGRFieldSubType &eSubType)
    1087             : {
    1088        2775 :     OGRFieldType eFType = OFTString;
    1089        2775 :     if (eType == GMLPT_Untyped)
    1090           6 :         eFType = OFTString;
    1091        2769 :     else if (eType == GMLPT_String)
    1092        1240 :         eFType = OFTString;
    1093        1529 :     else if (eType == GMLPT_Integer)
    1094         410 :         eFType = OFTInteger;
    1095        1119 :     else if (eType == GMLPT_Boolean)
    1096             :     {
    1097         127 :         eFType = OFTInteger;
    1098         127 :         eSubType = OFSTBoolean;
    1099             :     }
    1100         992 :     else if (eType == GMLPT_Short)
    1101             :     {
    1102         122 :         eFType = OFTInteger;
    1103         122 :         eSubType = OFSTInt16;
    1104             :     }
    1105         870 :     else if (eType == GMLPT_Integer64)
    1106          78 :         eFType = OFTInteger64;
    1107         792 :     else if (eType == GMLPT_Real)
    1108         278 :         eFType = OFTReal;
    1109         514 :     else if (eType == GMLPT_Float)
    1110             :     {
    1111         116 :         eFType = OFTReal;
    1112         116 :         eSubType = OFSTFloat32;
    1113             :     }
    1114         398 :     else if (eType == GMLPT_StringList)
    1115          66 :         eFType = OFTStringList;
    1116         332 :     else if (eType == GMLPT_IntegerList)
    1117          25 :         eFType = OFTIntegerList;
    1118         307 :     else if (eType == GMLPT_BooleanList)
    1119             :     {
    1120           3 :         eFType = OFTIntegerList;
    1121           3 :         eSubType = OFSTBoolean;
    1122             :     }
    1123         304 :     else if (eType == GMLPT_Integer64List)
    1124           9 :         eFType = OFTInteger64List;
    1125         295 :     else if (eType == GMLPT_RealList)
    1126          15 :         eFType = OFTRealList;
    1127         280 :     else if (eType == GMLPT_Date)
    1128          89 :         eFType = OFTDate;
    1129         191 :     else if (eType == GMLPT_Time)
    1130           4 :         eFType = OFTTime;
    1131         187 :     else if (eType == GMLPT_DateTime)
    1132         166 :         eFType = OFTDateTime;
    1133          21 :     else if (eType == GMLPT_FeaturePropertyList)
    1134          10 :         eFType = OFTStringList;
    1135        2775 :     return eFType;
    1136             : }
    1137             : 
    1138             : /************************************************************************/
    1139             : /*                       GML_FromOGRFieldType()                          */
    1140             : /************************************************************************/
    1141             : 
    1142          12 : GMLPropertyType GML_FromOGRFieldType(OGRFieldType eType,
    1143             :                                      OGRFieldSubType eSubType)
    1144             : {
    1145          12 :     GMLPropertyType type{GMLPT_Untyped};
    1146          12 :     switch (eType)
    1147             :     {
    1148           2 :         case OFTString:
    1149           2 :             type = GMLPT_String;
    1150           2 :             break;
    1151           2 :         case OFTInteger:
    1152             :         {
    1153           2 :             if (eSubType == OFSTBoolean)
    1154           0 :                 type = GMLPT_Boolean;
    1155           2 :             else if (eSubType == OFSTInt16)
    1156           2 :                 type = GMLPT_Short;
    1157             :             else
    1158           0 :                 type = GMLPT_Integer;
    1159           2 :             break;
    1160             :         }
    1161           8 :         case OFTReal:
    1162           8 :             type = GMLPT_Real;
    1163           8 :             break;
    1164           0 :         case OFTDate:
    1165           0 :             type = GMLPT_Date;
    1166           0 :             break;
    1167           0 :         case OFTDateTime:
    1168           0 :             type = GMLPT_DateTime;
    1169           0 :             break;
    1170           0 :         case OFTTime:
    1171           0 :             type = GMLPT_Time;
    1172           0 :             break;
    1173           0 :         default:
    1174           0 :             type = GMLPT_Untyped;
    1175           0 :             break;
    1176             :     }
    1177          12 :     return type;
    1178             : }

Generated by: LCOV version 1.14