LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gml - gmlfeatureclass.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 448 555 80.7 %
Date: 2024-05-06 22:33:47 Functions: 27 29 93.1 %

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

Generated by: LCOV version 1.14