LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/lvbag - ogrlvbaglayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 447 495 90.3 %
Date: 2024-05-13 13:33:37 Functions: 27 27 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  LV BAG Translator
       4             :  * Purpose:  Implements OGRLVBAGLayer.
       5             :  * Author:   Laixer B.V., info at laixer dot com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2021, Laixer B.V. <info at laixer dot com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_conv.h"
      30             : #include "ogr_geos.h"
      31             : #include "ogr_lvbag.h"
      32             : #include "ogr_p.h"
      33             : 
      34             : constexpr const char *pszSpecificationUrn = "urn:ogc:def:crs:EPSG::28992";
      35             : constexpr const size_t nDefaultIdentifierSize = 16;
      36             : 
      37             : /************************************************************************/
      38             : /*                           OGRLVBAGLayer()                            */
      39             : /*                                                                      */
      40             : /*      Note that the OGRLVBAGLayer assumes ownership of the passed     */
      41             : /*      file pointer.                                                   */
      42             : /************************************************************************/
      43             : 
      44          28 : OGRLVBAGLayer::OGRLVBAGLayer(const char *pszFilename, OGRLayerPool *poPoolIn,
      45          28 :                              char **papszOpenOptions)
      46             :     : OGRAbstractProxiedLayer{poPoolIn},
      47          28 :       poFeatureDefn{new OGRFeatureDefn{}}, fp{nullptr}, osFilename{pszFilename},
      48             :       eFileDescriptorsState{FD_CLOSED}, oParser{nullptr}, bSchemaOnly{false},
      49          56 :       bHasReadSchema{false}, bFixInvalidData{CPLFetchBool(
      50             :                                  papszOpenOptions, "AUTOCORRECT_INVALID_DATA",
      51             :                                  false)},
      52          56 :       bLegacyId{CPLFetchBool(papszOpenOptions, "LEGACY_ID", false)},
      53             :       nNextFID{0}, nCurrentDepth{0}, nGeometryElementDepth{0},
      54             :       nFeatureCollectionDepth{0}, nFeatureElementDepth{0},
      55             :       nAttributeElementDepth{0},
      56          56 :       eAddressRefState{AddressRefState::ADDRESS_PRIMARY}, bCollectData{false}
      57             : {
      58          28 :     SetDescription(CPLGetBasename(pszFilename));
      59             : 
      60          28 :     poFeatureDefn->Reference();
      61          28 : }
      62             : 
      63             : /************************************************************************/
      64             : /*                           ~OGRLVBAGLayer()                           */
      65             : /************************************************************************/
      66             : 
      67          56 : OGRLVBAGLayer::~OGRLVBAGLayer()
      68             : {
      69          28 :     delete m_poFeature;
      70          28 :     poFeatureDefn->Release();
      71          28 :     OGRLVBAGLayer::CloseUnderlyingLayer();
      72          56 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                            ResetReading()                            */
      76             : /************************************************************************/
      77             : 
      78         548 : void OGRLVBAGLayer::ResetReading()
      79             : {
      80         548 :     if (!TouchLayer())
      81           0 :         return;
      82             : 
      83         548 :     VSIRewindL(fp);
      84             : 
      85         548 :     nNextFID = 0;
      86         548 :     nCurrentDepth = 0;
      87         548 :     nGeometryElementDepth = 0;
      88         548 :     nFeatureCollectionDepth = 0;
      89         548 :     nFeatureElementDepth = 0;
      90         548 :     nAttributeElementDepth = 0;
      91         548 :     eAddressRefState = AddressRefState::ADDRESS_PRIMARY;
      92         548 :     bCollectData = false;
      93             : }
      94             : 
      95             : /************************************************************************/
      96             : /*                            GetLayerDefn()                            */
      97             : /************************************************************************/
      98             : 
      99        1789 : OGRFeatureDefn *OGRLVBAGLayer::GetLayerDefn()
     100             : {
     101        1789 :     if (!TouchLayer())
     102           0 :         return nullptr;
     103             : 
     104        1789 :     if (!bHasReadSchema)
     105             :     {
     106          26 :         bSchemaOnly = true;
     107             : 
     108          26 :         ConfigureParser();
     109          26 :         ParseDocument();
     110             :     }
     111             : 
     112        1789 :     return poFeatureDefn;
     113             : }
     114             : 
     115             : /************************************************************************/
     116             : /*                            XMLTagSplit()                             */
     117             : /************************************************************************/
     118             : 
     119        7864 : static inline const char *XMLTagSplit(const char *pszName)
     120             : {
     121        7864 :     const char *pszTag = pszName;
     122        7864 :     const char *pszSep = strchr(pszTag, ':');
     123        7864 :     if (pszSep)
     124        7864 :         pszTag = pszSep + 1;
     125             : 
     126        7864 :     return pszTag;
     127             : }
     128             : 
     129             : /************************************************************************/
     130             : /*                           AddSpatialRef()                            */
     131             : /************************************************************************/
     132             : 
     133          21 : void OGRLVBAGLayer::AddSpatialRef(OGRwkbGeometryType eTypeIn)
     134             : {
     135          21 :     OGRGeomFieldDefn *poGeomField = poFeatureDefn->GetGeomFieldDefn(0);
     136          21 :     OGRSpatialReference *poSRS = new OGRSpatialReference();
     137          21 :     poSRS->importFromURN(pszSpecificationUrn);
     138          21 :     poGeomField->SetSpatialRef(poSRS);
     139          21 :     poGeomField->SetType(eTypeIn);
     140          21 :     poSRS->Release();
     141          21 : }
     142             : 
     143             : /************************************************************************/
     144             : /*                      AddIdentifierFieldDefn()                        */
     145             : /************************************************************************/
     146             : 
     147          24 : void OGRLVBAGLayer::AddIdentifierFieldDefn()
     148             : {
     149          48 :     OGRFieldDefn oField0("identificatie", OFTString);
     150             : 
     151          24 :     poFeatureDefn->AddFieldDefn(&oField0);
     152          24 : }
     153             : 
     154             : /************************************************************************/
     155             : /*                       AddDocumentFieldDefn()                         */
     156             : /************************************************************************/
     157             : 
     158          24 : void OGRLVBAGLayer::AddDocumentFieldDefn()
     159             : {
     160          48 :     OGRFieldDefn oField0("status", OFTString);
     161          48 :     OGRFieldDefn oField1("geconstateerd", OFTInteger);
     162          24 :     oField1.SetSubType(OFSTBoolean);
     163          48 :     OGRFieldDefn oField2("documentDatum", OFTDate);
     164          48 :     OGRFieldDefn oField3("documentNummer", OFTString);
     165             : 
     166          24 :     poFeatureDefn->AddFieldDefn(&oField0);
     167          24 :     poFeatureDefn->AddFieldDefn(&oField1);
     168          24 :     poFeatureDefn->AddFieldDefn(&oField2);
     169          24 :     poFeatureDefn->AddFieldDefn(&oField3);
     170          24 : }
     171             : 
     172             : /************************************************************************/
     173             : /*                      AddOccurrenceFieldDefn()                        */
     174             : /************************************************************************/
     175             : 
     176          24 : void OGRLVBAGLayer::AddOccurrenceFieldDefn()
     177             : {
     178          48 :     OGRFieldDefn oField0("voorkomenIdentificatie", OFTInteger);
     179          48 :     OGRFieldDefn oField1("beginGeldigheid", OFTDate);
     180          48 :     OGRFieldDefn oField2("eindGeldigheid", OFTDate);
     181          48 :     OGRFieldDefn oField3("tijdstipRegistratie", OFTDateTime);
     182          48 :     OGRFieldDefn oField4("eindRegistratie", OFTDateTime);
     183          48 :     OGRFieldDefn oField5("tijdstipInactief", OFTDateTime);
     184          48 :     OGRFieldDefn oField6("tijdstipRegistratieLV", OFTDateTime);
     185          48 :     OGRFieldDefn oField7("tijdstipEindRegistratieLV", OFTDateTime);
     186          48 :     OGRFieldDefn oField8("tijdstipInactiefLV", OFTDateTime);
     187          48 :     OGRFieldDefn oField9("tijdstipNietBagLV", OFTDateTime);
     188             : 
     189          24 :     poFeatureDefn->AddFieldDefn(&oField0);
     190          24 :     poFeatureDefn->AddFieldDefn(&oField1);
     191          24 :     poFeatureDefn->AddFieldDefn(&oField2);
     192          24 :     poFeatureDefn->AddFieldDefn(&oField3);
     193          24 :     poFeatureDefn->AddFieldDefn(&oField4);
     194          24 :     poFeatureDefn->AddFieldDefn(&oField5);
     195          24 :     poFeatureDefn->AddFieldDefn(&oField6);
     196          24 :     poFeatureDefn->AddFieldDefn(&oField7);
     197          24 :     poFeatureDefn->AddFieldDefn(&oField8);
     198          24 :     poFeatureDefn->AddFieldDefn(&oField9);
     199          24 : }
     200             : 
     201             : /************************************************************************/
     202             : /*                         CreateFeatureDefn()                          */
     203             : /************************************************************************/
     204             : 
     205          24 : void OGRLVBAGLayer::CreateFeatureDefn(const char *pszDataset)
     206             : {
     207          24 :     if (EQUAL("pnd", pszDataset))
     208             :     {
     209          20 :         OGRFieldDefn oField0("oorspronkelijkBouwjaar", OFTInteger);
     210             : 
     211          10 :         poFeatureDefn->AddFieldDefn(&oField0);
     212             : 
     213          10 :         AddIdentifierFieldDefn();
     214          10 :         AddDocumentFieldDefn();
     215          10 :         AddOccurrenceFieldDefn();
     216             : 
     217          10 :         poFeatureDefn->SetName("Pand");
     218          10 :         SetDescription(poFeatureDefn->GetName());
     219             : 
     220          10 :         AddSpatialRef(wkbPolygon);
     221             :     }
     222          14 :     else if (EQUAL("num", pszDataset))
     223             :     {
     224           4 :         OGRFieldDefn oField0("huisnummer", OFTInteger);
     225           4 :         OGRFieldDefn oField1("huisletter", OFTString);
     226           4 :         OGRFieldDefn oField2("huisnummerToevoeging", OFTString);
     227           4 :         OGRFieldDefn oField3("postcode", OFTString);
     228           4 :         OGRFieldDefn oField4("typeAdresseerbaarObject", OFTString);
     229           4 :         OGRFieldDefn oField5("openbareruimteRef", OFTString);
     230           4 :         OGRFieldDefn oField6("woonplaatsRef", OFTString);
     231             : 
     232           2 :         poFeatureDefn->AddFieldDefn(&oField0);
     233           2 :         poFeatureDefn->AddFieldDefn(&oField1);
     234           2 :         poFeatureDefn->AddFieldDefn(&oField2);
     235           2 :         poFeatureDefn->AddFieldDefn(&oField3);
     236           2 :         poFeatureDefn->AddFieldDefn(&oField4);
     237           2 :         poFeatureDefn->AddFieldDefn(&oField5);
     238           2 :         poFeatureDefn->AddFieldDefn(&oField6);
     239             : 
     240           2 :         AddIdentifierFieldDefn();
     241           2 :         AddDocumentFieldDefn();
     242           2 :         AddOccurrenceFieldDefn();
     243             : 
     244           2 :         poFeatureDefn->SetName("Nummeraanduiding");
     245           2 :         SetDescription(poFeatureDefn->GetName());
     246             :     }
     247          12 :     else if (EQUAL("lig", pszDataset))
     248             :     {
     249           2 :         OGRFieldDefn oField0("hoofdadresNummeraanduidingRef", OFTString);
     250           2 :         OGRFieldDefn oField1("nevenadresNummeraanduidingRef", OFTStringList);
     251             : 
     252           1 :         poFeatureDefn->AddFieldDefn(&oField0);
     253           1 :         poFeatureDefn->AddFieldDefn(&oField1);
     254             : 
     255           1 :         AddIdentifierFieldDefn();
     256           1 :         AddDocumentFieldDefn();
     257           1 :         AddOccurrenceFieldDefn();
     258             : 
     259           1 :         poFeatureDefn->SetName("Ligplaats");
     260           1 :         SetDescription(poFeatureDefn->GetName());
     261             : 
     262           1 :         AddSpatialRef(wkbPolygon);
     263             :     }
     264          11 :     else if (EQUAL("sta", pszDataset))
     265             :     {
     266           4 :         OGRFieldDefn oField0("hoofdadresNummeraanduidingRef", OFTString);
     267           4 :         OGRFieldDefn oField1("nevenadresNummeraanduidingRef", OFTStringList);
     268             : 
     269           2 :         poFeatureDefn->AddFieldDefn(&oField0);
     270           2 :         poFeatureDefn->AddFieldDefn(&oField1);
     271             : 
     272           2 :         AddIdentifierFieldDefn();
     273           2 :         AddDocumentFieldDefn();
     274           2 :         AddOccurrenceFieldDefn();
     275             : 
     276           2 :         poFeatureDefn->SetName("Standplaats");
     277           2 :         SetDescription(poFeatureDefn->GetName());
     278             : 
     279           2 :         AddSpatialRef(wkbPolygon);
     280             :     }
     281           9 :     else if (EQUAL("opr", pszDataset))
     282             :     {
     283           2 :         OGRFieldDefn oField0("naam", OFTString);
     284           2 :         OGRFieldDefn oField1("type", OFTString);
     285           2 :         OGRFieldDefn oField2("woonplaatsRef", OFTString);
     286           2 :         OGRFieldDefn oField3("verkorteNaam", OFTString);
     287             : 
     288           1 :         poFeatureDefn->AddFieldDefn(&oField0);
     289           1 :         poFeatureDefn->AddFieldDefn(&oField1);
     290           1 :         poFeatureDefn->AddFieldDefn(&oField2);
     291           1 :         poFeatureDefn->AddFieldDefn(&oField3);
     292             : 
     293           1 :         AddIdentifierFieldDefn();
     294           1 :         AddDocumentFieldDefn();
     295           1 :         AddOccurrenceFieldDefn();
     296             : 
     297           1 :         poFeatureDefn->SetName("Openbareruimte");
     298           1 :         SetDescription(poFeatureDefn->GetName());
     299             :     }
     300           8 :     else if (EQUAL("vbo", pszDataset))
     301             :     {
     302          10 :         OGRFieldDefn oField0("gebruiksdoel", OFTStringList);
     303          10 :         OGRFieldDefn oField1("oppervlakte", OFTInteger);
     304          10 :         OGRFieldDefn oField2("hoofdadresNummeraanduidingRef", OFTString);
     305          10 :         OGRFieldDefn oField3("nevenadresNummeraanduidingRef", OFTStringList);
     306          10 :         OGRFieldDefn oField4("pandRef", OFTStringList);
     307             : 
     308           5 :         poFeatureDefn->AddFieldDefn(&oField0);
     309           5 :         poFeatureDefn->AddFieldDefn(&oField1);
     310           5 :         poFeatureDefn->AddFieldDefn(&oField2);
     311           5 :         poFeatureDefn->AddFieldDefn(&oField3);
     312           5 :         poFeatureDefn->AddFieldDefn(&oField4);
     313             : 
     314           5 :         AddIdentifierFieldDefn();
     315           5 :         AddDocumentFieldDefn();
     316           5 :         AddOccurrenceFieldDefn();
     317             : 
     318           5 :         poFeatureDefn->SetName("Verblijfsobject");
     319           5 :         SetDescription(poFeatureDefn->GetName());
     320             : 
     321           5 :         AddSpatialRef(wkbPoint);
     322             :     }
     323           3 :     else if (EQUAL("wpl", pszDataset))
     324             :     {
     325           6 :         OGRFieldDefn oField0("naam", OFTString);
     326             : 
     327           3 :         poFeatureDefn->AddFieldDefn(&oField0);
     328             : 
     329           3 :         AddIdentifierFieldDefn();
     330           3 :         AddDocumentFieldDefn();
     331           3 :         AddOccurrenceFieldDefn();
     332             : 
     333           3 :         poFeatureDefn->SetName("Woonplaats");
     334           3 :         SetDescription(poFeatureDefn->GetName());
     335             : 
     336           3 :         AddSpatialRef(wkbMultiPolygon);
     337             :     }
     338             :     else
     339           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     340             :                  "Parsing LV BAG extract failed : invalid layer definition");
     341          24 : }
     342             : 
     343             : /************************************************************************/
     344             : /*                         StartDataCollect()                           */
     345             : /************************************************************************/
     346             : 
     347        8457 : void OGRLVBAGLayer::StartDataCollect()
     348             : {
     349        8457 :     osElementString.Clear();
     350        8457 :     osAttributeString.Clear();
     351        8457 :     bCollectData = true;
     352        8457 : }
     353             : 
     354             : /************************************************************************/
     355             : /*                         StopDataCollect()                            */
     356             : /************************************************************************/
     357             : 
     358        8306 : void OGRLVBAGLayer::StopDataCollect()
     359             : {
     360        8306 :     bCollectData = false;
     361        8306 :     osElementString.Trim();
     362        8306 :     osAttributeString.Trim();
     363        8306 : }
     364             : 
     365             : /************************************************************************/
     366             : /*                           DataHandlerCbk()                           */
     367             : /************************************************************************/
     368             : 
     369       46986 : void OGRLVBAGLayer::DataHandlerCbk(const char *data, int nLen)
     370             : {
     371       46986 :     if (nLen && bCollectData)
     372       19200 :         osElementString.append(data, nLen);
     373       46986 : }
     374             : 
     375             : /************************************************************************/
     376             : /*                              TouchLayer()                            */
     377             : /************************************************************************/
     378             : 
     379        3020 : bool OGRLVBAGLayer::TouchLayer()
     380             : {
     381        3020 :     poPool->SetLastUsedLayer(this);
     382             : 
     383        3020 :     switch (eFileDescriptorsState)
     384             :     {
     385        2992 :         case FD_OPENED:
     386        2992 :             return true;
     387           0 :         case FD_CANNOT_REOPEN:
     388           0 :             return false;
     389          28 :         case FD_CLOSED:
     390          28 :             break;
     391             :     }
     392             : 
     393          28 :     fp = VSIFOpenExL(osFilename, "rb", true);
     394          28 :     if (!fp)
     395             :     {
     396           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     397             :                  "Opening LV BAG extract failed : %s", osFilename.c_str());
     398           0 :         eFileDescriptorsState = FD_CANNOT_REOPEN;
     399           0 :         return false;
     400             :     }
     401             : 
     402          28 :     eFileDescriptorsState = FD_OPENED;
     403             : 
     404          28 :     return true;
     405             : }
     406             : 
     407             : /************************************************************************/
     408             : /*                        CloseUnderlyingLayer()                        */
     409             : /************************************************************************/
     410             : 
     411          28 : void OGRLVBAGLayer::CloseUnderlyingLayer()
     412             : {
     413          28 :     if (fp)
     414          28 :         VSIFCloseL(fp);
     415          28 :     fp = nullptr;
     416             : 
     417          28 :     eFileDescriptorsState = FD_CLOSED;
     418          28 : }
     419             : 
     420             : /************************************************************************/
     421             : /*                        startElementCbk()                            */
     422             : /************************************************************************/
     423             : 
     424       14164 : void OGRLVBAGLayer::StartElementCbk(const char *pszName, const char **ppszAttr)
     425             : {
     426       14164 :     if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
     427        9940 :         nGeometryElementDepth == 0 && EQUAL("objecten:geometrie", pszName))
     428             :     {
     429         418 :         nGeometryElementDepth = nCurrentDepth;
     430         418 :         StartDataCollect();
     431             :     }
     432       13746 :     else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
     433        9522 :              nGeometryElementDepth + 1 == nCurrentDepth &&
     434         521 :              !STARTS_WITH_CI(pszName, "gml"))
     435             :     {
     436         103 :         nGeometryElementDepth = nCurrentDepth;
     437         103 :         StartDataCollect();
     438             :     }
     439       13643 :     else if (nFeatureElementDepth > 0 && nAttributeElementDepth == 0 &&
     440         527 :              nGeometryElementDepth == 0 && STARTS_WITH_CI(pszName, "objecten"))
     441         527 :         nAttributeElementDepth = nCurrentDepth;
     442       13116 :     else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
     443        9419 :              nGeometryElementDepth == 0 &&
     444        7761 :              (EQUAL("objecten:identificatie", pszName) ||
     445        7234 :               STARTS_WITH_CI(pszName, "objecten-ref")))
     446             :     {
     447         699 :         StartDataCollect();
     448         699 :         const char **papszIter = ppszAttr;
     449         699 :         while (papszIter && *papszIter != nullptr)
     450             :         {
     451         699 :             if (EQUAL("domein", papszIter[0]))
     452             :             {
     453         699 :                 osAttributeString = papszIter[1];
     454         699 :                 break;
     455             :             }
     456           0 :             papszIter += 2;
     457         699 :         }
     458             :     }
     459       12417 :     else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
     460        8720 :              nGeometryElementDepth == 0 &&
     461        7062 :              EQUAL("objecten:heeftalshoofdadres", pszName))
     462          21 :         eAddressRefState = AddressRefState::ADDRESS_PRIMARY;
     463       12396 :     else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
     464        8699 :              nGeometryElementDepth == 0 &&
     465        7041 :              EQUAL("objecten:heeftalsnevenadres", pszName))
     466           1 :         eAddressRefState = AddressRefState::ADDRESS_SECONDARY;
     467       12395 :     else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
     468        8698 :              nGeometryElementDepth == 0)
     469        7040 :         StartDataCollect();
     470        5355 :     else if (nGeometryElementDepth > 0 && STARTS_WITH_CI(pszName, "gml"))
     471             :     {
     472        1658 :         osElementString += "<";
     473        1658 :         osElementString += pszName;
     474             : 
     475        1658 :         const char **papszIter = ppszAttr;
     476        3315 :         while (papszIter && *papszIter != nullptr)
     477             :         {
     478        1657 :             OGRGeomFieldDefn *poGeomField = poFeatureDefn->GetGeomFieldDefn(0);
     479        2075 :             if (EQUAL("srsname", papszIter[0]) &&
     480         418 :                 poGeomField->GetSpatialRef() == nullptr)
     481             :             {
     482           0 :                 OGRSpatialReference *poSRS = new OGRSpatialReference();
     483           0 :                 poSRS->importFromURN(papszIter[1]);
     484           0 :                 poGeomField->SetSpatialRef(poSRS);
     485           0 :                 poSRS->Release();
     486             :             }
     487             : 
     488        1657 :             osElementString += " ";
     489        1657 :             osElementString += papszIter[0];
     490        1657 :             osElementString += "=\"";
     491        1657 :             osElementString += papszIter[1];
     492        1657 :             osElementString += "\"";
     493        1657 :             papszIter += 2;
     494             :         }
     495             : 
     496        1658 :         osElementString += ">";
     497             :     }
     498        3697 :     else if (nFeatureCollectionDepth > 0 && nFeatureElementDepth == 0 &&
     499        2304 :              EQUAL("sl-bag-extract:bagObject", pszName) && bHasReadSchema)
     500             :     {
     501         527 :         nFeatureElementDepth = nCurrentDepth;
     502         527 :         m_poFeature = new OGRFeature(poFeatureDefn);
     503         527 :         m_poFeature->SetFID(nNextFID++);
     504             :     }
     505        3170 :     else if (nFeatureCollectionDepth == 0 && EQUAL("sl:standBestand", pszName))
     506         199 :         nFeatureCollectionDepth = nCurrentDepth;
     507        2971 :     else if (nFeatureCollectionDepth > 0 && EQUAL("sl:objectType", pszName))
     508         197 :         StartDataCollect();
     509             : 
     510       14164 :     nCurrentDepth++;
     511       14164 : }
     512             : 
     513             : /************************************************************************/
     514             : /*                           endElementCbk()                            */
     515             : /************************************************************************/
     516             : 
     517       13905 : void OGRLVBAGLayer::EndElementCbk(const char *pszName)
     518             : {
     519       13905 :     nCurrentDepth--;
     520             : 
     521       13905 :     if (nCurrentDepth > nAttributeElementDepth && nAttributeElementDepth > 0 &&
     522        9940 :         nGeometryElementDepth == 0)
     523             :     {
     524        7864 :         const char *pszTag = XMLTagSplit(pszName);
     525             : 
     526        7864 :         StopDataCollect();
     527        7864 :         if (!osElementString.empty())
     528             :         {
     529        6008 :             int iFieldIndex = poFeatureDefn->GetFieldIndex(pszTag);
     530             : 
     531        6008 :             if (EQUAL("nummeraanduidingref", pszTag))
     532             :             {
     533          24 :                 switch (eAddressRefState)
     534             :                 {
     535           3 :                     case AddressRefState::ADDRESS_SECONDARY:
     536           6 :                         iFieldIndex = poFeatureDefn->GetFieldIndex(
     537           3 :                             "nevenadresnummeraanduidingref");
     538           3 :                         break;
     539             : 
     540          21 :                     default:
     541          42 :                         iFieldIndex = poFeatureDefn->GetFieldIndex(
     542          21 :                             "hoofdadresnummeraanduidingref");
     543          21 :                         break;
     544             :                 }
     545             :             }
     546             : 
     547        6008 :             if (EQUAL("identificatie", pszTag) ||
     548        5481 :                 STARTS_WITH_CI(pszName, "objecten-ref"))
     549             :             {
     550         699 :                 bool bIsIdInvalid = false;
     551         699 :                 if (osElementString.size() == nDefaultIdentifierSize - 1)
     552             :                 {
     553           2 :                     osElementString = '0' + osElementString;
     554             :                 }
     555         697 :                 else if (osElementString.size() > nDefaultIdentifierSize)
     556             :                 {
     557           0 :                     bIsIdInvalid = true;
     558           0 :                     m_poFeature->SetFieldNull(iFieldIndex);
     559           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     560             :                              "Invalid identificatie : %s, value set to null",
     561             :                              osElementString.c_str());
     562             :                 }
     563         699 :                 if (!bIsIdInvalid)
     564             :                 {
     565         699 :                     if (!bLegacyId && !osAttributeString.empty())
     566             :                     {
     567             :                         osElementString =
     568         699 :                             osAttributeString + '.' + osElementString;
     569             :                     }
     570             :                 }
     571             :             }
     572             : 
     573        6008 :             if (iFieldIndex > -1)
     574             :             {
     575             :                 const OGRFieldDefn *poFieldDefn =
     576        6008 :                     poFeatureDefn->GetFieldDefn(iFieldIndex);
     577        6008 :                 if (poFieldDefn->GetType() == OFTStringList)
     578             :                 {
     579          20 :                     if (m_poFeature->IsFieldSetAndNotNull(iFieldIndex))
     580             :                     {
     581          10 :                         CPLStringList aoList;
     582             :                         char **papszIter =
     583           5 :                             m_poFeature->GetFieldAsStringList(iFieldIndex);
     584          11 :                         while (papszIter != nullptr && *papszIter != nullptr)
     585             :                         {
     586           6 :                             aoList.AddString(*papszIter);
     587           6 :                             papszIter++;
     588             :                         }
     589             : 
     590           5 :                         aoList.AddString(osElementString.c_str());
     591           5 :                         m_poFeature->UnsetField(iFieldIndex);
     592           5 :                         m_poFeature->SetField(iFieldIndex, aoList.List());
     593             :                     }
     594             :                     else
     595          15 :                         m_poFeature->SetField(iFieldIndex,
     596             :                                               osElementString.c_str());
     597             :                 }
     598        5988 :                 else if (poFieldDefn->GetSubType() ==
     599             :                          OGRFieldSubType::OFSTBoolean)
     600             :                 {
     601         527 :                     if (EQUAL("n", osElementString.c_str()))
     602         527 :                         m_poFeature->SetField(iFieldIndex, 0);
     603           0 :                     else if (EQUAL("j", osElementString.c_str()))
     604           0 :                         m_poFeature->SetField(iFieldIndex, 1);
     605             :                     else
     606             :                     {
     607           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     608             :                                  "Parsing boolean failed");
     609           0 :                         XML_StopParser(oParser.get(), XML_FALSE);
     610             :                     }
     611             :                 }
     612             :                 else
     613        5461 :                     m_poFeature->SetField(iFieldIndex, osElementString.c_str());
     614             : 
     615        6086 :                 if (bFixInvalidData && (poFieldDefn->GetType() == OFTDate ||
     616          78 :                                         poFieldDefn->GetType() == OFTDateTime))
     617             :                 {
     618             :                     int nYear;
     619          53 :                     m_poFeature->GetFieldAsDateTime(
     620             :                         iFieldIndex, &nYear, nullptr, nullptr, nullptr, nullptr,
     621             :                         static_cast<float *>(nullptr), nullptr);
     622          53 :                     if (nYear > 2100)
     623             :                     {
     624           0 :                         m_poFeature->SetFieldNull(iFieldIndex);
     625           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     626             :                                  "Invalid date : %s, value set to null",
     627             :                                  osElementString.c_str());
     628             :                     }
     629             :                 }
     630             :             }
     631        6008 :             osElementString.Clear();
     632        7864 :         }
     633             :     }
     634        6041 :     else if (nAttributeElementDepth == nCurrentDepth)
     635         651 :         nAttributeElementDepth = 0;
     636        5390 :     else if (nGeometryElementDepth > 0 && nCurrentDepth > nGeometryElementDepth)
     637             :     {
     638        1658 :         osElementString += "</";
     639        1658 :         osElementString += pszName;
     640        1658 :         osElementString += ">";
     641             :     }
     642        3732 :     else if (nGeometryElementDepth == nCurrentDepth)
     643             :     {
     644         418 :         StopDataCollect();
     645         418 :         if (!osElementString.empty())
     646             :         {
     647             :             std::unique_ptr<OGRGeometry> poGeom =
     648             :                 std::unique_ptr<OGRGeometry>(OGRGeometry::FromHandle(
     649         836 :                     OGR_G_CreateFromGML(osElementString.c_str())));
     650         418 :             if (poGeom && !poGeom->IsEmpty())
     651             :             {
     652             :                 // The specification only accounts for 2-dimensional datasets
     653         418 :                 if (poGeom->Is3D())
     654         308 :                     poGeom->flattenTo2D();
     655             : 
     656             : #ifdef HAVE_GEOS
     657         418 :                 if (!poGeom->IsValid() && bFixInvalidData)
     658             :                 {
     659             :                     std::unique_ptr<OGRGeometry> poSubGeom =
     660           8 :                         std::unique_ptr<OGRGeometry>{poGeom->MakeValid()};
     661           4 :                     if (poSubGeom && poSubGeom->IsValid())
     662           4 :                         poGeom.reset(poSubGeom.release());
     663             :                 }
     664             : #endif
     665             : 
     666             :                 OGRGeomFieldDefn *poGeomField =
     667         418 :                     poFeatureDefn->GetGeomFieldDefn(0);
     668         418 :                 if (!poGeomField->GetSpatialRef())
     669           0 :                     poGeomField->SetSpatialRef(poGeom->getSpatialReference());
     670         418 :                 if (poGeomField->GetType() == wkbUnknown)
     671           0 :                     poGeomField->SetType(poGeom->getGeometryType());
     672             : 
     673         418 :                 if (poGeomField->GetType() == wkbPoint)
     674             :                 {
     675           7 :                     switch (poGeom->getGeometryType())
     676             :                     {
     677           0 :                         case wkbPolygon:
     678             :                         case wkbMultiPolygon:
     679             :                         {
     680           0 :                             auto poPoint = std::make_unique<OGRPoint>();
     681             : #ifdef HAVE_GEOS
     682           0 :                             if (poGeom->Centroid(poPoint.get()) == OGRERR_NONE)
     683           0 :                                 poGeom.reset(poPoint.release());
     684             : #else
     685             :                             CPLError(CE_Warning, CPLE_AppDefined,
     686             :                                      "Cannot shape geometry, GEOS support not "
     687             :                                      "enabled.");
     688             :                             poGeom.reset(poPoint.release());
     689             : #endif
     690           0 :                             break;
     691             :                         }
     692             : 
     693           7 :                         default:
     694           7 :                             break;
     695             :                     }
     696             :                 }
     697         507 :                 else if (poGeomField->GetType() == wkbMultiPolygon &&
     698          96 :                          poGeom->getGeometryType() == wkbPolygon)
     699             :                 {
     700         192 :                     auto poMultiPolygon = std::make_unique<OGRMultiPolygon>();
     701          96 :                     poMultiPolygon->addGeometry(poGeom.get());
     702          96 :                     poGeom.reset(poMultiPolygon.release());
     703             :                 }
     704         315 :                 else if (poGeomField->GetType() == wkbMultiPolygon &&
     705           0 :                          poGeom->getGeometryType() == wkbGeometryCollection &&
     706           0 :                          poGeom->toGeometryCollection()->getNumGeometries() >
     707         315 :                              0 &&
     708             :                          poGeom->toGeometryCollection()
     709           0 :                                  ->getGeometryRef(0)
     710           0 :                                  ->getGeometryType() == wkbPolygon)
     711             :                 {
     712           0 :                     auto poMultiPolygon = std::make_unique<OGRMultiPolygon>();
     713           0 :                     for (const auto &poChildGeom :
     714           0 :                          poGeom->toGeometryCollection())
     715           0 :                         poMultiPolygon->addGeometry(poChildGeom);
     716           0 :                     poGeom.reset(poMultiPolygon.release());
     717             :                 }
     718         630 :                 else if (poGeomField->GetType() == wkbPolygon &&
     719         315 :                          (poGeom->getGeometryType() == wkbMultiPolygon ||
     720         312 :                           poGeom->getGeometryType() == wkbGeometryCollection))
     721             :                 {
     722           4 :                     const OGRPolygon *poSubGeomLargest = nullptr;
     723           8 :                     for (const auto &poChildGeom :
     724          12 :                          poGeom->toGeometryCollection())
     725             :                     {
     726           8 :                         if (poChildGeom->getGeometryType() == wkbPolygon)
     727             :                         {
     728           7 :                             if (!poSubGeomLargest)
     729           4 :                                 poSubGeomLargest = poChildGeom->toPolygon();
     730           3 :                             else if (poChildGeom->toPolygon()->get_Area() >
     731           3 :                                      poSubGeomLargest->get_Area())
     732           0 :                                 poSubGeomLargest = poChildGeom->toPolygon();
     733             :                         }
     734             :                     }
     735           4 :                     if (poSubGeomLargest)
     736           4 :                         poGeom.reset(poSubGeomLargest->clone());
     737             :                 }
     738             : 
     739         418 :                 if (poGeomField->GetSpatialRef())
     740         836 :                     poGeom->assignSpatialReference(
     741         418 :                         poGeomField->GetSpatialRef());
     742         418 :                 m_poFeature->SetGeometryDirectly(poGeom.release());
     743             :             }
     744             :             else
     745             :             {
     746           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     747             :                          "Parsing geometry as GML failed");
     748           0 :                 XML_StopParser(oParser.get(), XML_FALSE);
     749             :             }
     750             :         }
     751             : 
     752         418 :         osElementString.Clear();
     753         418 :         osAttributeString.Clear();
     754         418 :         nGeometryElementDepth = 0;
     755             :     }
     756        3314 :     else if (nFeatureElementDepth == nCurrentDepth)
     757             :     {
     758         527 :         nFeatureElementDepth = 0;
     759         527 :         XML_StopParser(oParser.get(), XML_TRUE);
     760             :     }
     761        2787 :     else if (nFeatureCollectionDepth == nCurrentDepth)
     762         124 :         nFeatureCollectionDepth = 0;
     763        2663 :     else if (EQUAL("sl:objecttype", pszName) && !poFeatureDefn->GetFieldCount())
     764             :     {
     765          24 :         StopDataCollect();
     766          24 :         if (osElementString.empty())
     767             :         {
     768           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     769             :                      "Parsing LV BAG extract failed");
     770           0 :             XML_StopParser(oParser.get(), XML_FALSE);
     771             :         }
     772             : 
     773          24 :         if (!bHasReadSchema)
     774          24 :             CreateFeatureDefn(osElementString.c_str());
     775          24 :         bHasReadSchema = true;
     776             : 
     777             :         // The parser is suspended but never resumed. Stop
     778             :         // without resume indicated an error.
     779          24 :         if (bSchemaOnly)
     780          24 :             XML_StopParser(oParser.get(), XML_TRUE);
     781             :     }
     782       13905 : }
     783             : 
     784             : /************************************************************************/
     785             : /*                          ConfigureParser()                           */
     786             : /************************************************************************/
     787             : 
     788         199 : void OGRLVBAGLayer::ConfigureParser()
     789             : {
     790         199 :     ResetReading();
     791             : 
     792             :     const auto startElementWrapper =
     793       14164 :         [](void *pUserData, const char *pszName, const char **ppszAttr)
     794             :     {
     795       14164 :         static_cast<OGRLVBAGLayer *>(pUserData)->StartElementCbk(pszName,
     796             :                                                                  ppszAttr);
     797       14164 :     };
     798             : 
     799       13905 :     const auto endElementWrapper = [](void *pUserData, const char *pszName)
     800       13905 :     { static_cast<OGRLVBAGLayer *>(pUserData)->EndElementCbk(pszName); };
     801             : 
     802             :     const auto dataHandlerWrapper =
     803       46986 :         [](void *pUserData, const XML_Char *data, int nLen)
     804       46986 :     { static_cast<OGRLVBAGLayer *>(pUserData)->DataHandlerCbk(data, nLen); };
     805             : 
     806         199 :     oParser = OGRExpatUniquePtr{OGRCreateExpatXMLParser()};
     807         199 :     XML_SetElementHandler(oParser.get(), startElementWrapper,
     808             :                           endElementWrapper);
     809         199 :     XML_SetCharacterDataHandler(oParser.get(), dataHandlerWrapper);
     810         199 :     XML_SetUserData(oParser.get(), this);
     811         199 : }
     812             : 
     813             : /************************************************************************/
     814             : /*                         IsParserFinished()                           */
     815             : /************************************************************************/
     816             : 
     817        1218 : bool OGRLVBAGLayer::IsParserFinished(XML_Status status)
     818             : {
     819        1218 :     switch (status)
     820             :     {
     821         665 :         case XML_STATUS_OK:
     822         665 :             return false;
     823             : 
     824           2 :         case XML_STATUS_ERROR:
     825           2 :             CPLError(
     826             :                 CE_Failure, CPLE_AppDefined,
     827             :                 "Parsing of LV BAG file failed : %s at line %d, "
     828             :                 "column %d",
     829             :                 XML_ErrorString(XML_GetErrorCode(oParser.get())),
     830           2 :                 static_cast<int>(XML_GetCurrentLineNumber(oParser.get())),
     831           2 :                 static_cast<int>(XML_GetCurrentColumnNumber(oParser.get())));
     832             : 
     833           2 :             delete m_poFeature;
     834           2 :             m_poFeature = nullptr;
     835           2 :             return true;
     836             : 
     837         551 :         case XML_STATUS_SUSPENDED:
     838         551 :             return true;
     839             :     }
     840             : 
     841           0 :     return true;
     842             : }
     843             : 
     844             : /************************************************************************/
     845             : /*                           ParseDocument()                            */
     846             : /************************************************************************/
     847             : 
     848        1345 : void OGRLVBAGLayer::ParseDocument()
     849             : {
     850             :     while (true)
     851             :     {
     852             :         XML_ParsingStatus status;
     853        1345 :         XML_GetParsingStatus(oParser.get(), &status);
     854        1345 :         switch (status.parsing)
     855             :         {
     856         740 :             case XML_INITIALIZED:
     857             :             case XML_PARSING:
     858             :             {
     859             :                 const unsigned int nLen = static_cast<unsigned int>(
     860         740 :                     VSIFReadL(aBuf.data(), 1, aBuf.size(), fp));
     861             : 
     862         740 :                 if (IsParserFinished(XML_Parse(oParser.get(), aBuf.data(), nLen,
     863             :                                                VSIFEofL(fp))))
     864         680 :                     return;
     865             : 
     866         399 :                 break;
     867             :             }
     868             : 
     869         478 :             case XML_SUSPENDED:
     870             :             {
     871         478 :                 if (IsParserFinished(XML_ResumeParser(oParser.get())))
     872         212 :                     return;
     873             : 
     874         266 :                 break;
     875             :             }
     876             : 
     877         127 :             case XML_FINISHED:
     878             :             default:
     879         127 :                 return;
     880             :         }
     881         665 :     }
     882             : }
     883             : 
     884             : /************************************************************************/
     885             : /*                           GetNextFeature()                           */
     886             : /************************************************************************/
     887             : 
     888         546 : OGRFeature *OGRLVBAGLayer::GetNextFeature()
     889             : {
     890         546 :     if (!TouchLayer())
     891           0 :         return nullptr;
     892             : 
     893         546 :     if (!bHasReadSchema)
     894             :     {
     895           4 :         GetLayerDefn();
     896           4 :         if (!bHasReadSchema)
     897             :         {
     898           1 :             CPLError(
     899             :                 CE_Failure, CPLE_AppDefined,
     900             :                 "Parsing LV BAG extract failed : invalid layer definition");
     901           1 :             return nullptr;
     902             :         }
     903             :     }
     904             : 
     905         545 :     return OGRGetNextFeatureThroughRaw<OGRLVBAGLayer>::GetNextFeature();
     906             : }
     907             : 
     908             : /************************************************************************/
     909             : /*                         GetNextRawFeature()                          */
     910             : /************************************************************************/
     911             : 
     912         654 : OGRFeature *OGRLVBAGLayer::GetNextRawFeature()
     913             : {
     914         654 :     bSchemaOnly = false;
     915             : 
     916         654 :     if (nNextFID == 0)
     917         173 :         ConfigureParser();
     918             : 
     919         654 :     if (m_poFeature)
     920             :     {
     921           0 :         delete m_poFeature;
     922           0 :         m_poFeature = nullptr;
     923             :     }
     924             : 
     925         654 :     ParseDocument();
     926         654 :     OGRFeature *poFeatureRet = m_poFeature;
     927         654 :     m_poFeature = nullptr;
     928         654 :     return poFeatureRet;
     929             : }
     930             : 
     931             : /************************************************************************/
     932             : /*                           TestCapability()                           */
     933             : /************************************************************************/
     934             : 
     935         109 : int OGRLVBAGLayer::TestCapability(const char *pszCap)
     936             : {
     937         109 :     if (!TouchLayer())
     938           0 :         return FALSE;
     939             : 
     940         109 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
     941          39 :         return TRUE;
     942             : 
     943          70 :     return FALSE;
     944             : }

Generated by: LCOV version 1.14