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

Generated by: LCOV version 1.14