LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/nas - nashandler.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 217 329 66.0 %
Date: 2024-11-21 22:18:42 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Project:  NAS Reader
       4             :  * Purpose:  Implementation of NASHandler class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  **********************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam
       9             :  * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include <ctype.h>
      15             : #include "nasreaderp.h"
      16             : #include "cpl_conv.h"
      17             : #include "cpl_string.h"
      18             : #include "ogr_xerces.h"
      19             : 
      20             : #define NASDebug(fmt, ...)                                                     \
      21             :     CPLDebugOnly("NAS", "%s:%d %s " fmt, __FILE__, __LINE__, __FUNCTION__,     \
      22             :                  __VA_ARGS__)
      23             : 
      24             : /*
      25             :   Update modes:
      26             : 
      27             : GID<7
      28             :     <wfs:Transaction version="1.0.0" service="WFS">
      29             :         <wfs:Delete typeName="AX_BesondereFlurstuecksgrenze">
      30             :             <ogc:Filter>
      31             :                 <ogc:FeatureId fid="DENW18AL0000nANA20120117T130819Z" />
      32             :             </ogc:Filter>
      33             :         </wfs:Delete>
      34             :         <wfsext:Replace vendorId="AdV" safeToIgnore="false">
      35             :             <AP_PTO gml:id="DENW18AL0000pewY20131011T071138Z">
      36             :                 [...]
      37             :             </AP_PTO>
      38             :             <ogc:Filter>
      39             :                 <ogc:FeatureId fid="DENW18AL0000pewY20120117T143330Z" />
      40             :             </ogc:Filter>
      41             :         </wfsext:Replace>
      42             :         <wfs:Update typeName="AX_KommunalesGebiet">
      43             :             <wfs:Property>
      44             :                 <wfs:Name>adv:lebenszeitintervall/adv:AA_Lebenszeitintervall/adv:endet</wfs:Name>
      45             :                 <wfs:Value>2012-08-14T12:32:30Z</wfs:Value>
      46             :             </wfs:Property>
      47             :             <wfs:Property>
      48             :                 <wfs:Name>adv:anlass</wfs:Name>
      49             :                 <wfs:Value>000000</wfs:Value>
      50             :             </wfs:Property>
      51             :             <wfs:Property>
      52             :                 <wfs:Name>adv:anlass</wfs:Name>
      53             :                 <wfs:Value>010102</wfs:Value>
      54             :             </wfs:Property>
      55             :             <ogc:Filter>
      56             :                 <ogc:FeatureId fid="DENW11AL000062WD20111016T122010Z" />
      57             :             </ogc:Filter>
      58             :         </wfs:Update>
      59             :     </wfs:Transaction>
      60             : 
      61             : GID>=7
      62             :     <wfs:Transaction>
      63             :         <wfs:Insert>
      64             :             <AX_Flurstueck gml:id="DEBY0000F0000001">
      65             :                 …
      66             :             </AX_Flurstueck>
      67             :             <AX_Gebaeude gml:id="DEBY0000G0000001">
      68             :                 …
      69             :             </AX_Gebaeude>
      70             :         </wfs:Insert>
      71             :         <wfs:Replace>
      72             :             <AX_Flurstueck gml:id="DEBY0000F0000002">
      73             :                 …
      74             :             </AX_Flurstueck>
      75             :             <fes:Filter>
      76             :                 <fes:ResourceId rid="DEBY0000F000000220010101T000000Z"/>
      77             :             </fes:Filter>
      78             :         </wfs:Replace>
      79             :         <wfs:Delete typeNames=“AX_Buchungsstelle”>
      80             :             <fes:Filter>
      81             :                 <fes:ResourceId rid="DEBY0000B000000320010101T000000Z"/>
      82             :                 <fes:ResourceId rid="DEBY0000B000000420010101T000000Z"/>
      83             :                 …
      84             :             </fes:Filter>
      85             :         </wfs:Delete>
      86             :         <wfs:Update typeNames="adv:AX_Flurstueck">
      87             :             <wfs:Property>
      88             :                 <wfs:ValueReference>adv:lebenszeitintervall/adv:AA_Lebenszeitintervall/adv:endet</wfs:ValueReference>
      89             :                     <wfs:Value>2007-11-13T12:00:00Z</wfs:Value>
      90             :                 </wfs:Property>
      91             :             <wfs:Property>
      92             :             <wfs:ValueReference>adv:anlass</wfs:ValueReference>
      93             :                  <wfs:Value>000000</wfs:Value>
      94             :             </wfs:Property>
      95             :             <wfs:Property>
      96             :                  <wfs:ValueReference>adv:anlass</wfs:ValueReference>
      97             :                  <wfs:Value>010102</wfs:Value>
      98             :             </wfs:Property>
      99             :             <wfs:Filter>
     100             :                  <fes:ResourceId rid="DEBY123412345678"/>
     101             :             </wfs:Filter>
     102             :         </wfs:Update>
     103             :     </wfs:Transaction>
     104             : */
     105             : 
     106             : /************************************************************************/
     107             : /*                             NASHandler()                             */
     108             : /************************************************************************/
     109             : 
     110           8 : NASHandler::NASHandler(NASReader *poReader)
     111             :     : m_poReader(poReader), m_pszCurField(nullptr), m_pszGeometry(nullptr),
     112             :       m_nGeomAlloc(0), m_nGeomLen(0), m_nGeometryDepth(0),
     113             :       m_nGeometryPropertyIndex(-1), m_nDepth(0), m_nDepthFeature(0),
     114           8 :       m_bIgnoreFeature(false), m_Locator(nullptr)
     115             : {
     116           8 : }
     117             : 
     118             : /************************************************************************/
     119             : /*                            ~NASHandler()                             */
     120             : /************************************************************************/
     121             : 
     122          16 : NASHandler::~NASHandler()
     123             : 
     124             : {
     125           8 :     CPLFree(m_pszCurField);
     126           8 :     CPLFree(m_pszGeometry);
     127          16 : }
     128             : 
     129             : /************************************************************************/
     130             : /*                        GetAttributes()                               */
     131             : /************************************************************************/
     132             : 
     133         120 : CPLString NASHandler::GetAttributes(const Attributes *attrs)
     134             : {
     135         120 :     CPLString osRes;
     136             : 
     137         144 :     for (unsigned int i = 0; i < attrs->getLength(); i++)
     138             :     {
     139          24 :         osRes += " ";
     140          24 :         osRes += transcode(attrs->getQName(i));
     141          24 :         osRes += "=\"";
     142          24 :         osRes += transcode(attrs->getValue(i));
     143          24 :         osRes += "\"";
     144             :     }
     145         120 :     return osRes;
     146             : }
     147             : 
     148             : /************************************************************************/
     149             : /*                   setDocumentLocator()                               */
     150             : /************************************************************************/
     151             : 
     152           8 : void NASHandler::setDocumentLocator(const Locator *locator)
     153             : {
     154           8 :     m_Locator = locator;
     155           8 :     return DefaultHandler::setDocumentLocator(locator);
     156             : }
     157             : 
     158             : /************************************************************************/
     159             : /*                            startElement()                            */
     160             : /************************************************************************/
     161             : 
     162         571 : void NASHandler::startElement(const XMLCh *const /* uri */,
     163             :                               const XMLCh *const localname,
     164             :                               const XMLCh *const /* qname */,
     165             :                               const Attributes &attrs)
     166             : 
     167             : {
     168         571 :     m_nEntityCounter = 0;
     169             : 
     170         571 :     GMLReadState *poState = m_poReader->GetState();
     171             : 
     172         571 :     transcode(localname, m_osElementName);
     173             : 
     174         571 :     NASDebug("element=%s poState=%s m_nDepth=%d m_nDepthFeature=%d context=%s",
     175             :              m_osElementName.c_str(), poState ? "(state)" : "(no state)",
     176             :              m_nDepth, m_nDepthFeature, m_osDeleteContext.c_str());
     177             : 
     178         571 :     m_nDepth++;
     179         571 :     if (m_bIgnoreFeature && m_nDepth > m_nDepthFeature)
     180          93 :         return;
     181             : 
     182         478 :     if (m_nDepthFeature == 0)
     183             :     {
     184         199 :         if (m_osElementName == "Replace")
     185             :         {
     186           4 :             const XMLCh achSafeToIgnore[] = {'s', 'a', 'f', 'e', 'T', 'o', 'I',
     187             :                                              'g', 'n', 'o', 'r', 'e', 0};
     188           4 :             int nIndex = attrs.getIndex(achSafeToIgnore);
     189           4 :             if (nIndex != -1)
     190           4 :                 transcode(attrs.getValue(nIndex), m_osSafeToIgnore);
     191             :             else
     192           0 :                 m_osSafeToIgnore = "true";
     193           4 :             m_osReplacingFID = "";
     194             : 
     195           4 :             CPLAssert(m_osDeleteContext == "");
     196           4 :             m_osDeleteContext = m_osElementName;
     197             :         }
     198         195 :         else if (m_osElementName == "Update" || m_osElementName == "Delete")
     199             :         {
     200           4 :             const XMLCh achTypeNames[] = {'t', 'y', 'p', 'e', 'N',
     201             :                                           'a', 'm', 'e', 's', 0};
     202           4 :             const XMLCh achTypeName[] = {'t', 'y', 'p', 'e', 'N',
     203             :                                          'a', 'm', 'e', 0};
     204           4 :             int nIndex = attrs.getIndex(achTypeNames);
     205           4 :             if (nIndex == -1)
     206           4 :                 nIndex = attrs.getIndex(achTypeName);
     207             : 
     208           4 :             if (nIndex == -1)
     209             :             {
     210           0 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
     211             :                          "NAS: expected type name missing at %s:%d:%d",
     212           0 :                          m_poReader->GetSourceFileName(),
     213           0 :                          static_cast<int>(m_Locator->getLineNumber()),
     214           0 :                          static_cast<int>(m_Locator->getColumnNumber()));
     215           0 :                 return;
     216             :             }
     217             : 
     218           4 :             transcode(attrs.getValue(nIndex), m_osTypeName);
     219             : 
     220           4 :             const char *pszTypeName = strchr(m_osTypeName.c_str(), ':');
     221           4 :             pszTypeName = pszTypeName ? pszTypeName + 1 : m_osTypeName.c_str();
     222           4 :             m_osTypeName = pszTypeName;
     223             : 
     224           4 :             CPLAssert(m_osDeleteContext == "");
     225           4 :             m_osDeleteContext = m_osElementName;
     226             :         }
     227         191 :         else if (m_osDeleteContext == "Update" &&
     228           0 :                  (m_osElementName == "Name" ||
     229           0 :                   m_osElementName == "ValueReference" ||
     230           0 :                   m_osElementName == "Value"))
     231             :         {
     232             :             // fetch value
     233           0 :             CPLFree(m_pszCurField);
     234           0 :             m_pszCurField = CPLStrdup("");
     235             :         }
     236         209 :         else if (m_osDeleteContext != "" && (m_osElementName == "ResourceId" ||
     237          18 :                                              m_osElementName == "FeatureId"))
     238             :         {
     239             :             const char *pszFilteredClassName =
     240           7 :                 m_poReader->GetFilteredClassName();
     241           7 :             if (!pszFilteredClassName || EQUAL(pszFilteredClassName, "Delete"))
     242             :             {
     243           7 :                 const XMLCh achRid[] = {'r', 'i', 'd', 0};
     244           7 :                 const XMLCh achFid[] = {'f', 'i', 'd', 0};
     245           7 :                 if (m_osTypeName == "")
     246             :                 {
     247           0 :                     CPLError(CE_Failure, CPLE_AssertionFailed,
     248             :                              "NAS: type name(s) missing at %s:%d:%d",
     249           0 :                              m_poReader->GetSourceFileName(),
     250           0 :                              static_cast<int>(m_Locator->getLineNumber()),
     251           0 :                              static_cast<int>(m_Locator->getColumnNumber()));
     252           0 :                     return;
     253             :                 }
     254             : 
     255           7 :                 int nIndex = attrs.getIndex(
     256           7 :                     m_osElementName == "ResourceId" ? achRid : achFid);
     257           7 :                 if (nIndex == -1)
     258             :                 {
     259           0 :                     CPLError(CE_Failure, CPLE_AssertionFailed,
     260             :                              "NAS: expected feature id missing at %s,%d:%d",
     261           0 :                              m_poReader->GetSourceFileName(),
     262           0 :                              static_cast<int>(m_Locator->getLineNumber()),
     263           0 :                              static_cast<int>(m_Locator->getColumnNumber()));
     264           0 :                     return;
     265             :                 }
     266             : 
     267          14 :                 CPLString osFeatureId;
     268           7 :                 transcode(attrs.getValue(nIndex), osFeatureId);
     269             : 
     270           7 :                 m_poReader->PushFeature("Delete", attrs);
     271           7 :                 m_poReader->SetFeaturePropertyDirectly("typeName",
     272             :                                                        CPLStrdup(m_osTypeName));
     273           7 :                 m_poReader->SetFeaturePropertyDirectly(
     274             :                     "context", CPLStrdup(m_osDeleteContext));
     275           7 :                 m_poReader->SetFeaturePropertyDirectly("FeatureId",
     276             :                                                        CPLStrdup(osFeatureId));
     277             : 
     278           7 :                 if (m_osDeleteContext == "Replace")
     279             :                 {
     280           3 :                     if (m_osReplacingFID == "")
     281             :                     {
     282           0 :                         CPLError(
     283             :                             CE_Failure, CPLE_AssertionFailed,
     284             :                             "NAS: replacing feature id not set at %s:%d:%d",
     285           0 :                             m_poReader->GetSourceFileName(),
     286           0 :                             static_cast<int>(m_Locator->getLineNumber()),
     287           0 :                             static_cast<int>(m_Locator->getColumnNumber()));
     288           0 :                         return;
     289             :                     }
     290             : 
     291           3 :                     m_poReader->SetFeaturePropertyDirectly(
     292             :                         "replacedBy", CPLStrdup(m_osReplacingFID));
     293           3 :                     m_poReader->SetFeaturePropertyDirectly(
     294             :                         "safeToIgnore", CPLStrdup(m_osSafeToIgnore));
     295           3 :                     m_osReplacingFID = "";
     296           3 :                     m_osSafeToIgnore = "";
     297             :                 }
     298           4 :                 else if (m_osDeleteContext == "Update")
     299             :                 {
     300           0 :                     m_poReader->SetFeaturePropertyDirectly(
     301             :                         "endet", CPLStrdup(m_osUpdateEnds));
     302           0 :                     for (std::list<CPLString>::iterator it =
     303           0 :                              m_UpdateOccasions.begin();
     304           0 :                          it != m_UpdateOccasions.end(); ++it)
     305             :                     {
     306           0 :                         m_poReader->SetFeaturePropertyDirectly("anlass",
     307           0 :                                                                CPLStrdup(*it));
     308             :                     }
     309             : 
     310           0 :                     m_osUpdateEnds = "";
     311           0 :                     m_UpdateOccasions.clear();
     312             :                 }
     313             : 
     314           7 :                 return;
     315             :             }
     316             :             else
     317             :             {
     318             :                 // we don't issue Delete features
     319           0 :                 m_osDeleteContext = "";
     320             :             }
     321             :         }
     322         184 :         else if (m_poReader->IsFeatureElement(m_osElementName))
     323             :         {
     324           4 :             m_nDepthFeature = m_nDepth - 1;
     325             : 
     326             :             // record id of replacing feature
     327           4 :             if (m_osDeleteContext == "Replace")
     328             :             {
     329           4 :                 const XMLCh achGmlId[] = {'g', 'm', 'l', ':', 'i', 'd', 0};
     330           4 :                 int nIndex = attrs.getIndex(achGmlId);
     331           4 :                 if (nIndex == -1)
     332             :                 {
     333           0 :                     CPLError(CE_Failure, CPLE_AssertionFailed,
     334             :                              "NAS: id of replacing feature not set at %s:%d:%d",
     335           0 :                              m_poReader->GetSourceFileName(),
     336           0 :                              static_cast<int>(m_Locator->getLineNumber()),
     337           0 :                              static_cast<int>(m_Locator->getColumnNumber()));
     338           0 :                     m_bIgnoreFeature = true;
     339           0 :                     return;
     340             :                 }
     341             : 
     342           4 :                 CPLAssert(m_osReplacingFID == "");
     343           4 :                 transcode(attrs.getValue(nIndex), m_osReplacingFID);
     344             :             }
     345             : 
     346           4 :             m_osTypeName = m_osElementName;
     347             : 
     348             :             const char *pszFilteredClassName =
     349           4 :                 m_poReader->GetFilteredClassName();
     350           6 :             m_bIgnoreFeature = pszFilteredClassName &&
     351           2 :                                !EQUAL(m_osElementName, pszFilteredClassName);
     352             : 
     353           4 :             if (!m_bIgnoreFeature)
     354           3 :                 m_poReader->PushFeature(m_osElementName, attrs);
     355             : 
     356           4 :             return;
     357             :         }
     358             :     }
     359         279 :     else if (m_pszGeometry != nullptr || IsGeometryElement(m_osElementName))
     360             :     {
     361         240 :         if (m_nGeometryPropertyIndex == -1 && poState->m_poFeature &&
     362         120 :             poState->m_poFeature->GetClass())
     363             :         {
     364         120 :             GMLFeatureClass *poClass = poState->m_poFeature->GetClass();
     365         120 :             m_nGeometryPropertyIndex =
     366         120 :                 poClass->GetGeometryPropertyIndexBySrcElement(
     367             :                     poState->osPath.c_str());
     368             :         }
     369             : 
     370         120 :         const int nLNLen = static_cast<int>(m_osElementName.size());
     371         120 :         CPLString osAttributes = GetAttributes(&attrs);
     372             : 
     373             :         /* should save attributes too! */
     374             : 
     375         120 :         if (m_pszGeometry == nullptr)
     376           3 :             m_nGeometryDepth = poState->m_nPathLength;
     377             : 
     378         237 :         if (m_pszGeometry == nullptr ||
     379         117 :             m_nGeomLen + nLNLen + 4 + (int)osAttributes.size() > m_nGeomAlloc)
     380             :         {
     381           3 :             m_nGeomAlloc =
     382           3 :                 (int)(m_nGeomAlloc * 1.3 + nLNLen + osAttributes.size() + 1000);
     383           3 :             m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
     384             :         }
     385             : 
     386         120 :         strcpy(m_pszGeometry + m_nGeomLen, "<");
     387         120 :         strcpy(m_pszGeometry + m_nGeomLen + 1, m_osElementName);
     388             : 
     389         120 :         if (!osAttributes.empty())
     390             :         {
     391          24 :             strcat(m_pszGeometry + m_nGeomLen, " ");
     392          24 :             strcat(m_pszGeometry + m_nGeomLen, osAttributes);
     393             :         }
     394             : 
     395         120 :         strcat(m_pszGeometry + m_nGeomLen, ">");
     396         120 :         m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
     397             :     }
     398         159 :     else if (m_poReader->IsAttributeElement(m_osElementName, attrs))
     399             :     {
     400         159 :         m_poReader->DealWithAttributes(
     401         159 :             m_osElementName, static_cast<int>(m_osElementName.length()), attrs);
     402         159 :         CPLFree(m_pszCurField);
     403         159 :         m_pszCurField = CPLStrdup("");
     404             :     }
     405             : 
     406         467 :     poState->PushPath(m_osElementName);
     407             : 
     408         467 :     if (poState->osPath.size() > 512)
     409             :     {
     410           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     411             :                  "NAS: Too long path. Stop parsing at %s:%d:%d",
     412           0 :                  m_poReader->GetSourceFileName(),
     413           0 :                  static_cast<int>(m_Locator->getLineNumber()),
     414           0 :                  static_cast<int>(m_Locator->getColumnNumber()));
     415           0 :         m_poReader->StopParsing();
     416             :     }
     417             : }
     418             : 
     419             : /************************************************************************/
     420             : /*                             endElement()                             */
     421             : /************************************************************************/
     422         555 : void NASHandler::endElement(const XMLCh *const /* uri */,
     423             :                             const XMLCh *const localname,
     424             :                             const XMLCh *const /* qname */)
     425             : 
     426             : {
     427         555 :     m_nEntityCounter = 0;
     428             : 
     429         555 :     GMLReadState *poState = m_poReader->GetState();
     430             : 
     431         555 :     transcode(localname, m_osElementName);
     432             : 
     433         555 :     NASDebug("element=%s poState=%s m_nDepth=%d m_nDepthFeature=%d context=%s",
     434             :              m_osElementName.c_str(), poState ? "(state)" : "(no state)",
     435             :              m_nDepth, m_nDepthFeature, m_osDeleteContext.c_str());
     436             : 
     437         555 :     m_nDepth--;
     438         555 :     if (m_bIgnoreFeature && m_nDepth >= m_nDepthFeature)
     439             :     {
     440          94 :         if (m_nDepth == m_nDepthFeature)
     441             :         {
     442           1 :             m_bIgnoreFeature = false;
     443           1 :             m_nDepthFeature = 0;
     444             :         }
     445          94 :         return;
     446             :     }
     447             : 
     448         461 :     if (m_osDeleteContext == "Update")
     449             :     {
     450           0 :         if (m_osElementName == "Name" || m_osElementName == "ValueReference")
     451             :         {
     452             :             const char *pszName;
     453           0 :             pszName = strrchr(m_pszCurField, '/');
     454           0 :             pszName = pszName ? pszName + 1 : m_pszCurField;
     455           0 :             pszName = strrchr(pszName, ':');
     456           0 :             pszName = pszName ? pszName + 1 : m_pszCurField;
     457             : 
     458           0 :             CPLAssert(m_osUpdatePropertyName == "");
     459           0 :             m_osUpdatePropertyName = pszName;
     460           0 :             CPLFree(m_pszCurField);
     461           0 :             m_pszCurField = nullptr;
     462             : 
     463           0 :             if (m_osUpdatePropertyName != "endet" &&
     464           0 :                 m_osUpdatePropertyName != "anlass")
     465             :             {
     466           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     467             :                          "NAS: Unexpected property name %s at %s:%d:%d",
     468             :                          m_osUpdatePropertyName.c_str(),
     469           0 :                          m_poReader->GetSourceFileName(),
     470           0 :                          static_cast<int>(m_Locator->getLineNumber()),
     471           0 :                          static_cast<int>(m_Locator->getColumnNumber()));
     472           0 :                 m_osUpdatePropertyName = "";
     473             :             }
     474             :         }
     475           0 :         else if (m_osElementName == "Value")
     476             :         {
     477           0 :             CPLAssert(m_osUpdatePropertyName != "");
     478           0 :             if (m_osUpdatePropertyName == "endet")
     479           0 :                 m_osUpdateEnds = m_pszCurField;
     480           0 :             else if (m_osUpdatePropertyName == "anlass")
     481           0 :                 m_UpdateOccasions.push_back(m_pszCurField);
     482           0 :             m_osUpdatePropertyName = "";
     483           0 :             CPLFree(m_pszCurField);
     484           0 :             m_pszCurField = nullptr;
     485             :         }
     486             :     }
     487         461 :     else if (m_pszCurField != nullptr && poState->m_poFeature != nullptr)
     488             :     {
     489          87 :         m_poReader->SetFeaturePropertyDirectly(poState->osPath.c_str(),
     490             :                                                m_pszCurField);
     491          87 :         m_pszCurField = nullptr;
     492             :     }
     493             : 
     494             :     /* -------------------------------------------------------------------- */
     495             :     /*      If we are collecting Geometry than store it, and consider if    */
     496             :     /*      this is the end of the geometry.                                */
     497             :     /* -------------------------------------------------------------------- */
     498         461 :     if (m_pszGeometry != nullptr)
     499             :     {
     500         120 :         int nLNLen = static_cast<int>(m_osElementName.size());
     501             : 
     502             :         /* should save attributes too! */
     503             : 
     504         120 :         if (m_nGeomLen + nLNLen + 4 > m_nGeomAlloc)
     505             :         {
     506           0 :             m_nGeomAlloc = (int)(m_nGeomAlloc * 1.3 + nLNLen + 1000);
     507           0 :             m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
     508             :         }
     509             : 
     510         120 :         strcat(m_pszGeometry + m_nGeomLen, "</");
     511         120 :         strcpy(m_pszGeometry + m_nGeomLen + 2, m_osElementName);
     512         120 :         strcat(m_pszGeometry + m_nGeomLen + nLNLen + 2, ">");
     513         120 :         m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
     514             : 
     515         120 :         if (poState->m_nPathLength == m_nGeometryDepth + 1)
     516             :         {
     517           3 :             if (poState->m_poFeature != nullptr)
     518             :             {
     519           3 :                 CPLXMLNode *psNode = CPLParseXMLString(m_pszGeometry);
     520           3 :                 if (psNode)
     521             :                 {
     522             :                     /* workaround for common malformed gml:pos with just a
     523             :                      * elevation value instead of a full 3D coordinate:
     524             :                      *
     525             :                      * <gml:Point gml:id="BII2H">
     526             :                      *    <gml:pos
     527             :                      * srsName="urn:adv:crs:ETRS89_h">41.394</gml:pos>
     528             :                      * </gml:Point>
     529             :                      *
     530             :                      */
     531             :                     const char *pszPos =
     532           3 :                         CPLGetXMLValue(psNode, "=Point.pos", nullptr);
     533           3 :                     if (pszPos != nullptr && strstr(pszPos, " ") == nullptr)
     534             :                     {
     535           0 :                         CPLSetXMLValue(psNode, "pos",
     536             :                                        CPLSPrintf("0 0 %s", pszPos));
     537             :                     }
     538             : 
     539           0 :                     if (m_nGeometryPropertyIndex >= 0 &&
     540           0 :                         m_nGeometryPropertyIndex <
     541           3 :                             poState->m_poFeature->GetGeometryCount() &&
     542           0 :                         poState->m_poFeature
     543           0 :                             ->GetGeometryList()[m_nGeometryPropertyIndex])
     544             :                     {
     545             :                         int iId =
     546           0 :                             poState->m_poFeature->GetClass()->GetPropertyIndex(
     547             :                                 "gml_id");
     548             :                         const GMLProperty *poIdProp =
     549           0 :                             poState->m_poFeature->GetProperty(iId);
     550             : #ifdef DEBUG_VERBOSE
     551             :                         char *pszOldGeom = CPLSerializeXMLTree(
     552             :                             poState->m_poFeature
     553             :                                 ->GetGeometryList()[m_nGeometryPropertyIndex]);
     554             : 
     555             :                         NASDebug(
     556             :                             "Overwriting other geometry (%s; replace:%s; "
     557             :                             "with:%s) at %s:%d:%d",
     558             :                             poIdProp && poIdProp->nSubProperties > 0 &&
     559             :                                     poIdProp->papszSubProperties[0]
     560             :                                 ? poIdProp->papszSubProperties[0]
     561             :                                 : "(null)",
     562             :                             m_pszGeometry, pszOldGeom,
     563             :                             m_poReader->GetSourceFileName(),
     564             :                             static_cast<int>(m_Locator->getLineNumber()),
     565             :                             static_cast<int>(m_Locator->getColumnNumber()));
     566             : 
     567             :                         CPLFree(pszOldGeom);
     568             : #else
     569           0 :                         CPLError(
     570             :                             CE_Warning, CPLE_AppDefined,
     571             :                             "NAS: Overwriting other geometry (%s) at %s:%d:%d",
     572           0 :                             poIdProp && poIdProp->nSubProperties > 0 &&
     573           0 :                                     poIdProp->papszSubProperties[0]
     574           0 :                                 ? poIdProp->papszSubProperties[0]
     575             :                                 : "(null)",
     576           0 :                             m_poReader->GetSourceFileName(),
     577           0 :                             static_cast<int>(m_Locator->getLineNumber()),
     578           0 :                             static_cast<int>(m_Locator->getColumnNumber()));
     579             : #endif
     580             :                     }
     581             : 
     582           3 :                     if (m_nGeometryPropertyIndex >= 0)
     583           0 :                         poState->m_poFeature->SetGeometryDirectly(
     584             :                             m_nGeometryPropertyIndex, psNode);
     585             : 
     586             :                     // no geometry property or property without element path
     587           6 :                     else if (poState->m_poFeature->GetClass()
     588           5 :                                      ->GetGeometryPropertyCount() == 0 ||
     589           1 :                              (poState->m_poFeature->GetClass()
     590           2 :                                       ->GetGeometryPropertyCount() == 1 &&
     591           1 :                               poState->m_poFeature->GetClass()
     592             :                                   ->GetGeometryProperty(0)
     593           1 :                                   ->GetSrcElement() &&
     594           1 :                               *poState->m_poFeature->GetClass()
     595             :                                       ->GetGeometryProperty(0)
     596           1 :                                       ->GetSrcElement() == 0))
     597           3 :                         poState->m_poFeature->SetGeometryDirectly(psNode);
     598             : 
     599             :                     else
     600             :                     {
     601           0 :                         CPLError(
     602             :                             CE_Warning, CPLE_AssertionFailed,
     603             :                             "NAS: Unexpected geometry skipped (class:%s "
     604             :                             "path:%s geom:%s) at %s:%d:%d",
     605           0 :                             poState->m_poFeature->GetClass()->GetName(),
     606             :                             poState->osPath.c_str(), m_pszGeometry,
     607           0 :                             m_poReader->GetSourceFileName(),
     608           0 :                             static_cast<int>(m_Locator->getLineNumber()),
     609           0 :                             static_cast<int>(m_Locator->getColumnNumber()));
     610           0 :                         CPLDestroyXMLNode(psNode);
     611             :                     }
     612             :                 }
     613             :                 else
     614           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     615             :                              "NAS: Invalid geometry skipped at %s:%d:%d",
     616           0 :                              m_poReader->GetSourceFileName(),
     617           0 :                              static_cast<int>(m_Locator->getLineNumber()),
     618           0 :                              static_cast<int>(m_Locator->getColumnNumber()));
     619             :             }
     620             :             else
     621           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     622             :                          "NAS: Skipping geometry without feature at %s:%d:%d",
     623           0 :                          m_poReader->GetSourceFileName(),
     624           0 :                          static_cast<int>(m_Locator->getLineNumber()),
     625           0 :                          static_cast<int>(m_Locator->getColumnNumber()));
     626             : 
     627           3 :             CPLFree(m_pszGeometry);
     628           3 :             m_pszGeometry = nullptr;
     629           3 :             m_nGeomAlloc = m_nGeomLen = 0;
     630           3 :             m_nGeometryPropertyIndex = -1;
     631             :         }
     632             :     }
     633             : 
     634             :     // Finished actual feature or ResourceId/FeatureId of Delete/Replace/Update operation
     635           7 :     if ((m_nDepth == m_nDepthFeature && poState->m_poFeature != nullptr &&
     636           3 :          EQUAL(m_osElementName,
     637        1218 :                poState->m_poFeature->GetClass()->GetElementName())) ||
     638         754 :         (m_osDeleteContext != "" &&
     639         592 :          (m_osElementName == "ResourceId" || m_osElementName == "FeatureId")))
     640             :     {
     641          10 :         m_nDepthFeature = 0;
     642          10 :         m_poReader->PopState();
     643             :     }
     644             :     else
     645         451 :         poState->PopPath();
     646             : 
     647         461 :     if (m_osDeleteContext == m_osElementName)
     648             :     {
     649           5 :         m_osDeleteContext = "";
     650             :     }
     651             : }
     652             : 
     653             : /************************************************************************/
     654             : /*                             startEntity()                            */
     655             : /************************************************************************/
     656             : 
     657        1001 : void NASHandler::startEntity(const XMLCh *const /* name */)
     658             : {
     659        1001 :     m_nEntityCounter++;
     660        1001 :     if (m_nEntityCounter > 1000 && !m_poReader->HasStoppedParsing())
     661             :     {
     662             :         throw SAXNotSupportedException(
     663           1 :             "File probably corrupted (million laugh pattern)");
     664             :     }
     665        1000 : }
     666             : 
     667             : /************************************************************************/
     668             : /*                             characters()                             */
     669             : /************************************************************************/
     670             : 
     671        2056 : void NASHandler::characters(const XMLCh *const chars, const XMLSize_t length)
     672             : {
     673        2056 :     if (m_pszCurField != nullptr)
     674             :     {
     675         180 :         const int nCurFieldLength = static_cast<int>(strlen(m_pszCurField));
     676             : 
     677         180 :         int nSkipped = 0;
     678         180 :         if (nCurFieldLength == 0)
     679             :         {
     680             :             // Ignore white space
     681        1101 :             while (chars[nSkipped] == ' ' || chars[nSkipped] == 10 ||
     682        2100 :                    chars[nSkipped] == 13 || chars[nSkipped] == '\t')
     683         921 :                 nSkipped++;
     684             :         }
     685             : 
     686         180 :         transcode(chars + nSkipped, m_osCharacters,
     687         180 :                   static_cast<int>(length) - nSkipped);
     688             : 
     689         360 :         m_pszCurField = static_cast<char *>(CPLRealloc(
     690         180 :             m_pszCurField, nCurFieldLength + m_osCharacters.size() + 1));
     691         180 :         memcpy(m_pszCurField + nCurFieldLength, m_osCharacters.c_str(),
     692         180 :                m_osCharacters.size() + 1);
     693             :     }
     694             : 
     695        2056 :     if (m_pszGeometry != nullptr)
     696             :     {
     697         237 :         int nSkipped = 0;
     698         237 :         if (m_nGeomLen == 0)
     699             :         {
     700             :             // Ignore white space
     701           0 :             while (chars[nSkipped] == ' ' || chars[nSkipped] == 10 ||
     702           0 :                    chars[nSkipped] == 13 || chars[nSkipped] == '\t')
     703           0 :                 nSkipped++;
     704             :         }
     705             : 
     706         237 :         transcode(chars + nSkipped, m_osCharacters,
     707         237 :                   static_cast<int>(length) - nSkipped);
     708             : 
     709         237 :         const int nCharsLen = static_cast<int>(m_osCharacters.size());
     710             : 
     711         237 :         if (m_nGeomLen + nCharsLen * 4 + 4 > m_nGeomAlloc)
     712             :         {
     713           3 :             m_nGeomAlloc = (int)(m_nGeomAlloc * 1.3 + nCharsLen * 4 + 1000);
     714           3 :             m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
     715             :         }
     716             : 
     717         237 :         memcpy(m_pszGeometry + m_nGeomLen, m_osCharacters.c_str(),
     718         237 :                m_osCharacters.size() + 1);
     719         237 :         m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
     720             :     }
     721        2056 : }
     722             : 
     723             : /************************************************************************/
     724             : /*                             fatalError()                             */
     725             : /************************************************************************/
     726             : 
     727           0 : void NASHandler::fatalError(const SAXParseException &exception)
     728             : 
     729             : {
     730           0 :     CPLString osErrMsg;
     731           0 :     transcode(exception.getMessage(), osErrMsg);
     732           0 :     CPLError(CE_Failure, CPLE_AppDefined,
     733             :              "NAS: XML Parsing Error: %s at line %d, column %d\n",
     734           0 :              osErrMsg.c_str(), static_cast<int>(exception.getLineNumber()),
     735           0 :              static_cast<int>(exception.getColumnNumber()));
     736           0 : }
     737             : 
     738             : /************************************************************************/
     739             : /*                         IsGeometryElement()                          */
     740             : /************************************************************************/
     741             : 
     742         162 : bool NASHandler::IsGeometryElement(const char *pszElement)
     743             : 
     744             : {
     745         324 :     return strcmp(pszElement, "Polygon") == 0 ||
     746         162 :            strcmp(pszElement, "MultiPolygon") == 0 ||
     747         162 :            strcmp(pszElement, "MultiPoint") == 0 ||
     748         162 :            strcmp(pszElement, "MultiLineString") == 0 ||
     749         162 :            strcmp(pszElement, "MultiSurface") == 0 ||
     750         162 :            strcmp(pszElement, "GeometryCollection") == 0 ||
     751         162 :            strcmp(pszElement, "Point") == 0 ||
     752         162 :            strcmp(pszElement, "Curve") == 0 ||
     753         162 :            strcmp(pszElement, "MultiCurve") == 0 ||
     754         162 :            strcmp(pszElement, "CompositeCurve") == 0 ||
     755         162 :            strcmp(pszElement, "Surface") == 0 ||
     756         483 :            strcmp(pszElement, "PolygonPatch") == 0 ||
     757         321 :            strcmp(pszElement, "LineString") == 0;
     758             : }
     759             : 
     760             : // vim: set sw=4 expandtab ai :

Generated by: LCOV version 1.14