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

Generated by: LCOV version 1.14