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

Generated by: LCOV version 1.14