LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vfk - vfkdatablock.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 146 472 30.9 %
Date: 2026-02-10 10:01:39 Functions: 18 33 54.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  VFK Reader - Data block definition
       4             :  * Purpose:  Implements VFKDataBlock class.
       5             :  * Author:   Martin Landa, landa.martin gmail.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009-2013, Martin Landa <landa.martin gmail.com>
       9             :  * Copyright (c) 2012-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include <ctime>
      15             : 
      16             : #include "vfkreader.h"
      17             : #include "vfkreaderp.h"
      18             : 
      19             : #include "cpl_conv.h"
      20             : #include "cpl_error.h"
      21             : 
      22             : /*!
      23             :   \brief VFK Data Block constructor
      24             : 
      25             :   \param pszName data block name
      26             : */
      27        1037 : IVFKDataBlock::IVFKDataBlock(const char *pszName, const IVFKReader *poReader)
      28             :     : m_papoFeature(nullptr), m_nPropertyCount(0), m_papoProperty(nullptr),
      29        2074 :       m_pszName(CPLStrdup(pszName)),
      30             :       m_bGeometry(false),  // Geometry is not loaded by default.
      31             :       m_nGeometryType(wkbUnknown),
      32             :       m_bGeometryPerBlock(true),  // Load geometry per block/feature.
      33             :       m_nFeatureCount(-1),        // Load data on first request.
      34        1037 :       m_iNextFeature(-1), m_poReader(const_cast<IVFKReader *>(poReader))
      35             : {
      36        1037 :     m_nRecordCount[RecordValid] = 0L;    // Number of valid records.
      37        1037 :     m_nRecordCount[RecordSkipped] = 0L;  // Number of skipped (invalid) records.
      38        1037 :     m_nRecordCount[RecordDuplicated] = 0L;  // Number of duplicated records.
      39        1037 : }
      40             : 
      41             : /*!
      42             :   \brief VFKDataBlock destructor
      43             : */
      44        2074 : IVFKDataBlock::~IVFKDataBlock()
      45             : {
      46        1037 :     CPLFree(m_pszName);
      47             : 
      48       10846 :     for (int i = 0; i < m_nPropertyCount; i++)
      49             :     {
      50        9809 :         if (m_papoProperty[i])
      51        9809 :             delete m_papoProperty[i];
      52             :     }
      53        1037 :     CPLFree(m_papoProperty);
      54             : 
      55        2006 :     for (int i = 0; i < m_nFeatureCount; i++)
      56             :     {
      57         969 :         if (m_papoFeature[i])
      58         969 :             delete m_papoFeature[i];
      59             :     }
      60        1037 :     CPLFree(m_papoFeature);
      61        1037 : }
      62             : 
      63             : /*!
      64             :   \brief Get property definition
      65             : 
      66             :   \param iIndex property index
      67             : 
      68             :   \return pointer to VFKPropertyDefn definition or NULL on failure
      69             : */
      70       46373 : VFKPropertyDefn *IVFKDataBlock::GetProperty(int iIndex) const
      71             : {
      72       46373 :     if (iIndex < 0 || iIndex >= m_nPropertyCount)
      73           0 :         return nullptr;
      74             : 
      75       46373 :     return m_papoProperty[iIndex];
      76             : }
      77             : 
      78             : /*!
      79             :   \brief Set properties
      80             : 
      81             :   \param poLine pointer to line
      82             : */
      83        1037 : void IVFKDataBlock::SetProperties(const char *poLine)
      84             : {
      85             :     /* skip data block name */
      86        1037 :     const char *poChar = strchr(poLine, ';');
      87        1037 :     if (poChar == nullptr)
      88           0 :         return;
      89             : 
      90        1037 :     poChar++;
      91             : 
      92             :     /* read property name/type */
      93        1037 :     const char *poProp = poChar;
      94        1037 :     char *pszName = nullptr;
      95        1037 :     char *pszType = nullptr;
      96        1037 :     int nLength = 0;
      97      122315 :     while (*poChar != '\0')
      98             :     {
      99      121278 :         if (*poChar == ' ')
     100             :         {
     101        9809 :             pszName = (char *)CPLRealloc(pszName, nLength + 1);
     102        9809 :             strncpy(pszName, poProp, nLength);
     103        9809 :             pszName[nLength] = '\0';
     104             : 
     105        9809 :             poProp = ++poChar;
     106        9809 :             nLength = 0;
     107        9809 :             if (*poProp == '\0')
     108           0 :                 break;
     109             :         }
     110      111469 :         else if (*poChar == ';')
     111             :         {
     112        8772 :             pszType = (char *)CPLRealloc(pszType, nLength + 1);
     113        8772 :             strncpy(pszType, poProp, nLength);
     114        8772 :             pszType[nLength] = '\0';
     115             : 
     116             :             /* add property */
     117        8772 :             if (pszName && *pszName != '\0' && *pszType != '\0')
     118        8772 :                 AddProperty(pszName, pszType);
     119             : 
     120        8772 :             poProp = ++poChar;
     121        8772 :             nLength = 0;
     122        8772 :             if (*poProp == '\0')
     123           0 :                 break;
     124             :         }
     125      121278 :         poChar++;
     126      121278 :         nLength++;
     127             :     }
     128             : 
     129        1037 :     pszType = (char *)CPLRealloc(pszType, nLength + 1);
     130        1037 :     if (nLength > 0)
     131        1037 :         strncpy(pszType, poProp, nLength);
     132        1037 :     pszType[nLength] = '\0';
     133             : 
     134             :     /* add property */
     135        1037 :     if (pszName && *pszName != '\0' && *pszType != '\0')
     136        1037 :         AddProperty(pszName, pszType);
     137             : 
     138        1037 :     CPLFree(pszName);
     139        1037 :     CPLFree(pszType);
     140             : }
     141             : 
     142             : /*!
     143             :   \brief Add data block property
     144             : 
     145             :   \param pszName property name
     146             :   \param pszType property type
     147             : 
     148             :   \return number of properties
     149             : */
     150        9809 : int IVFKDataBlock::AddProperty(const char *pszName, const char *pszType)
     151             : {
     152             :     /* Force text attributes to avoid int64 overflow
     153             :        see https://github.com/OSGeo/gdal/issues/672 */
     154        9809 :     if (EQUAL(m_pszName, "VLA") &&
     155         204 :         (EQUAL(pszName, "PODIL_CITATEL") || EQUAL(pszName, "PODIL_JMENOVATEL")))
     156          34 :         pszType = "T30";
     157             : 
     158             :     VFKPropertyDefn *poNewProperty =
     159        9809 :         new VFKPropertyDefn(pszName, pszType, m_poReader->GetEncoding());
     160             : 
     161        9809 :     m_nPropertyCount++;
     162             : 
     163       19618 :     m_papoProperty = (VFKPropertyDefn **)CPLRealloc(
     164        9809 :         m_papoProperty, sizeof(VFKPropertyDefn *) * m_nPropertyCount);
     165        9809 :     m_papoProperty[m_nPropertyCount - 1] = poNewProperty;
     166             : 
     167        9809 :     return m_nPropertyCount;
     168             : }
     169             : 
     170             : /*!
     171             :   \brief Get number of features for given data block
     172             : 
     173             :   \param bForce true to force reading VFK data blocks if needed
     174             : 
     175             :   \return number of features
     176             : */
     177        2324 : GIntBig IVFKDataBlock::GetFeatureCount(bool bForce)
     178             : {
     179        2324 :     if (bForce && m_nFeatureCount == -1)
     180             :     {
     181           0 :         m_poReader->ReadDataRecords(this); /* read VFK data records */
     182           0 :         if (m_bGeometryPerBlock && !m_bGeometry)
     183             :         {
     184           0 :             LoadGeometry(); /* get real number of features */
     185             :         }
     186             :     }
     187             : #if defined(__GNUC__)
     188             : #pragma GCC diagnostic push
     189             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     190             : #endif
     191        2324 :     return m_nFeatureCount;
     192             : #if defined(__GNUC__)
     193             : #pragma GCC diagnostic pop
     194             : #endif
     195             : }
     196             : 
     197             : /*!
     198             :   \brief Set number of features per data block
     199             : 
     200             :   \param nNewCount number of features
     201             :   \param bIncrement increment current value
     202             : */
     203        1037 : void IVFKDataBlock::SetFeatureCount(int nNewCount, bool bIncrement)
     204             : {
     205        1037 :     if (bIncrement)
     206             :     {
     207           0 :         m_nFeatureCount += nNewCount;
     208             :     }
     209             :     else
     210             :     {
     211        1037 :         m_nFeatureCount = nNewCount;
     212             :     }
     213        1037 : }
     214             : 
     215             : /*!
     216             :   \brief Reset reading
     217             : 
     218             :   \param iIdx force index
     219             : */
     220           8 : void IVFKDataBlock::ResetReading(int iIdx)
     221             : {
     222           8 :     if (iIdx > -1)
     223             :     {
     224           0 :         m_iNextFeature = iIdx;
     225             :     }
     226             :     else
     227             :     {
     228           8 :         m_iNextFeature = 0;
     229             :     }
     230           8 : }
     231             : 
     232             : /*!
     233             :   \brief Get next feature
     234             : 
     235             :   \return pointer to VFKFeature instance or NULL on error
     236             : */
     237          34 : IVFKFeature *IVFKDataBlock::GetNextFeature()
     238             : {
     239          34 :     if (m_nFeatureCount < 0)
     240             :     {
     241           0 :         m_poReader->ReadDataRecords(this);
     242             :     }
     243             : 
     244          34 :     if (m_bGeometryPerBlock && !m_bGeometry)
     245             :     {
     246           0 :         LoadGeometry();
     247             :     }
     248             : 
     249          34 :     if (m_iNextFeature < 0)
     250           0 :         ResetReading();
     251             : 
     252          34 :     if (m_iNextFeature < 0 || m_iNextFeature >= m_nFeatureCount)
     253           3 :         return nullptr;
     254             : 
     255          31 :     return m_papoFeature[m_iNextFeature++];
     256             : }
     257             : 
     258             : /*!
     259             :   \brief Get previous feature
     260             : 
     261             :   \return pointer to VFKFeature instance or NULL on error
     262             : */
     263           0 : IVFKFeature *IVFKDataBlock::GetPreviousFeature()
     264             : {
     265           0 :     if (m_nFeatureCount < 0)
     266             :     {
     267           0 :         m_poReader->ReadDataRecords(this);
     268             :     }
     269             : 
     270           0 :     if (m_bGeometryPerBlock && !m_bGeometry)
     271             :     {
     272           0 :         LoadGeometry();
     273             :     }
     274             : 
     275           0 :     if (m_iNextFeature < 0)
     276           0 :         ResetReading();
     277             : 
     278           0 :     if (m_iNextFeature < 0 || m_iNextFeature >= m_nFeatureCount)
     279           0 :         return nullptr;
     280             : 
     281           0 :     return m_papoFeature[m_iNextFeature--];
     282             : }
     283             : 
     284             : /*!
     285             :   \brief Get first feature
     286             : 
     287             :   \return pointer to VFKFeature instance or NULL on error
     288             : */
     289           0 : IVFKFeature *IVFKDataBlock::GetFirstFeature()
     290             : {
     291           0 :     if (m_nFeatureCount < 0)
     292             :     {
     293           0 :         m_poReader->ReadDataRecords(this);
     294             :     }
     295             : 
     296           0 :     if (m_bGeometryPerBlock && !m_bGeometry)
     297             :     {
     298           0 :         LoadGeometry();
     299             :     }
     300             : 
     301           0 :     if (m_nFeatureCount < 1)
     302           0 :         return nullptr;
     303             : 
     304           0 :     return m_papoFeature[0];
     305             : }
     306             : 
     307             : /*!
     308             :   \brief Get last feature
     309             : 
     310             :   \return pointer to VFKFeature instance or NULL on error
     311             : */
     312           0 : IVFKFeature *IVFKDataBlock::GetLastFeature()
     313             : {
     314           0 :     if (m_nFeatureCount < 0)
     315             :     {
     316           0 :         m_poReader->ReadDataRecords(this);
     317             :     }
     318             : 
     319           0 :     if (m_bGeometryPerBlock && !m_bGeometry)
     320             :     {
     321           0 :         LoadGeometry();
     322             :     }
     323             : 
     324           0 :     if (m_nFeatureCount < 1)
     325           0 :         return nullptr;
     326             : 
     327           0 :     return m_papoFeature[m_nFeatureCount - 1];
     328             : }
     329             : 
     330             : /*!
     331             :   \brief Get property index by name
     332             : 
     333             :   \param pszName property name
     334             : 
     335             :   \return property index or -1 on error (property name not found)
     336             : */
     337         464 : int IVFKDataBlock::GetPropertyIndex(const char *pszName) const
     338             : {
     339        4176 :     for (int i = 0; i < m_nPropertyCount; i++)
     340        4176 :         if (EQUAL(pszName, m_papoProperty[i]->GetName()))
     341         464 :             return i;
     342             : 
     343           0 :     return -1;
     344             : }
     345             : 
     346             : /*!
     347             :   \brief Set geometry type (point, linestring, polygon)
     348             : 
     349             :   \param bSuppressGeometry True for forcing wkbNone type
     350             : 
     351             :   \return geometry type
     352             : */
     353        1037 : OGRwkbGeometryType IVFKDataBlock::SetGeometryType(bool bSuppressGeometry)
     354             : {
     355        1037 :     m_nGeometryType = wkbNone; /* pure attribute records */
     356        1037 :     if (bSuppressGeometry)
     357             :     {
     358          61 :         m_bGeometry = true; /* pretend that geometry is already loaded */
     359             : 
     360          61 :         return m_nGeometryType;
     361             :     }
     362             : 
     363         976 :     if (EQUAL(m_pszName, "SOBR") || EQUAL(m_pszName, "OBBP") ||
     364         944 :         EQUAL(m_pszName, "SPOL") || EQUAL(m_pszName, "OB") ||
     365         912 :         EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBPEJ"))
     366          96 :         m_nGeometryType = wkbPoint;
     367             : 
     368         880 :     else if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG") ||
     369         864 :              EQUAL(m_pszName, "HP") || EQUAL(m_pszName, "DPM") ||
     370         832 :              EQUAL(m_pszName, "ZVB"))
     371          64 :         m_nGeometryType = wkbLineString;
     372             : 
     373         816 :     else if (EQUAL(m_pszName, "PAR"))
     374          16 :         m_nGeometryType = wkbPolygon;
     375             : 
     376         800 :     else if (EQUAL(m_pszName, "BUD"))
     377          16 :         m_nGeometryType = wkbMultiPolygon;
     378             : 
     379         976 :     return m_nGeometryType;
     380             : }
     381             : 
     382             : /*!
     383             :   \brief Get geometry type
     384             : 
     385             :   \return geometry type
     386             : */
     387        6323 : OGRwkbGeometryType IVFKDataBlock::GetGeometryType() const
     388             : {
     389        6323 :     return m_nGeometryType;
     390             : }
     391             : 
     392             : /*!
     393             :   \brief Get feature by index
     394             : 
     395             :   \param iIndex feature index
     396             : 
     397             :   \return pointer to feature definition or NULL on failure
     398             : */
     399        1901 : IVFKFeature *IVFKDataBlock::GetFeatureByIndex(int iIndex) const
     400             : {
     401        1901 :     if (iIndex < 0 || iIndex >= m_nFeatureCount)
     402           0 :         return nullptr;
     403             : 
     404        1901 :     return m_papoFeature[iIndex];
     405             : }
     406             : 
     407             : /*!
     408             :   \brief Get feature by FID
     409             : 
     410             :   Modifies next feature id.
     411             : 
     412             :   \param nFID feature id
     413             : 
     414             :   \return pointer to feature definition or NULL on failure (not found)
     415             : */
     416           1 : IVFKFeature *IVFKDataBlock::GetFeature(GIntBig nFID)
     417             : {
     418           1 :     if (m_nFeatureCount < 0)
     419             :     {
     420           0 :         m_poReader->ReadDataRecords(this);
     421             :     }
     422             : 
     423           1 :     if (nFID < 1 || nFID > m_nFeatureCount)
     424           0 :         return nullptr;
     425             : 
     426           1 :     if (m_bGeometryPerBlock && !m_bGeometry)
     427             :     {
     428           0 :         LoadGeometry();
     429             :     }
     430             : 
     431           1 :     return GetFeatureByIndex(int(nFID) - 1); /* zero-based index */
     432             : }
     433             : 
     434             : /*!
     435             :   \brief Load geometry
     436             : 
     437             :   Print warning when some invalid features are detected.
     438             : 
     439             :   \return number of invalid features or -1 on failure
     440             : */
     441        1104 : int IVFKDataBlock::LoadGeometry()
     442             : {
     443             : #if defined(__GNUC__)
     444             : #pragma GCC diagnostic push
     445             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     446             : #endif
     447        1104 :     if (m_bGeometry)
     448         128 :         return 0;
     449             : #if defined(__GNUC__)
     450             : #pragma GCC diagnostic pop
     451             : #endif
     452             : 
     453         976 :     m_bGeometry = true;
     454         976 :     int nInvalid = 0;
     455             : 
     456             : #ifdef DEBUG_TIMING
     457             :     const clock_t start = clock();
     458             : #endif
     459             : 
     460         976 :     if (m_nFeatureCount < 0)
     461             :     {
     462           0 :         m_poReader->ReadDataRecords(this);
     463             :     }
     464             : 
     465         976 :     if (EQUAL(m_pszName, "SOBR") || EQUAL(m_pszName, "SPOL") ||
     466         944 :         EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBPEJ") ||
     467         912 :         EQUAL(m_pszName, "OB") || EQUAL(m_pszName, "OBBP"))
     468             :     {
     469             :         /* -> wkbPoint */
     470          96 :         nInvalid = LoadGeometryPoint();
     471             :     }
     472         880 :     else if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
     473             :     {
     474             :         /* -> wkbLineString */
     475          16 :         nInvalid = LoadGeometryLineStringSBP();
     476             :     }
     477         864 :     else if (EQUAL(m_pszName, "HP") || EQUAL(m_pszName, "DPM") ||
     478         832 :              EQUAL(m_pszName, "ZVB"))
     479             :     {
     480             :         /* -> wkbLineString */
     481          48 :         nInvalid = LoadGeometryLineStringHP();
     482             :     }
     483         816 :     else if (EQUAL(m_pszName, "PAR") || EQUAL(m_pszName, "BUD"))
     484             :     {
     485             :         /* -> wkbPolygon */
     486          32 :         nInvalid = LoadGeometryPolygon();
     487             :     }
     488             : 
     489             : #ifdef DEBUG_TIMING
     490             :     const clock_t end = clock();
     491             : #endif
     492             : 
     493         976 :     if (nInvalid > 0)
     494             :     {
     495           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     496             :                  "%s: %d features with invalid or empty geometry", m_pszName,
     497             :                  nInvalid);
     498             :     }
     499             : 
     500             : #ifdef DEBUG_TIMING
     501             :     CPLDebug("OGR-VFK", "VFKDataBlock::LoadGeometry(): name=%s time=%ld sec",
     502             :              m_pszName, (long)((end - start) / CLOCKS_PER_SEC));
     503             : #endif
     504             : 
     505         976 :     return nInvalid;
     506             : }
     507             : 
     508           0 : void IVFKDataBlock::FillPointList(PointList *poList,
     509             :                                   const OGRLineString *poLine)
     510             : {
     511           0 :     poList->reserve(poLine->getNumPoints());
     512             : 
     513             :     /* OGRLineString -> PointList */
     514           0 :     for (int i = 0; i < poLine->getNumPoints(); i++)
     515             :     {
     516           0 :         OGRPoint pt;
     517           0 :         poLine->getPoint(i, &pt);
     518           0 :         poList->emplace_back(std::move(pt));
     519             :     }
     520           0 : }
     521             : 
     522             : /*!
     523             :   \brief Add linestring to a ring (private)
     524             : 
     525             :   \param[in,out] papoRing list of rings
     526             :   \param poLine pointer to linestring to be added to a ring
     527             :   \param bNewRing  create new ring
     528             :   \param bBackward allow backward direction
     529             : 
     530             :   \return true on success or false on failure
     531             : */
     532           0 : bool IVFKDataBlock::AppendLineToRing(PointListArray *papoRing,
     533             :                                      const OGRLineString *poLine, bool bNewRing,
     534             :                                      bool bBackward)
     535             : {
     536             :     /* create new ring */
     537           0 :     if (bNewRing)
     538             :     {
     539           0 :         PointList *poList = new PointList();
     540           0 :         FillPointList(poList, poLine);
     541           0 :         papoRing->emplace_back(poList);
     542           0 :         return true;
     543             :     }
     544             : 
     545           0 :     if (poLine->getNumPoints() < 2)
     546           0 :         return false;
     547           0 :     OGRPoint oFirstNew;
     548           0 :     OGRPoint oLastNew;
     549           0 :     poLine->StartPoint(&oFirstNew);
     550           0 :     poLine->EndPoint(&oLastNew);
     551             : 
     552           0 :     for (PointList *ring : *papoRing)
     553             :     {
     554           0 :         const OGRPoint &oFirst = ring->front();
     555           0 :         const OGRPoint &oLast = ring->back();
     556             : 
     557           0 :         if (oFirstNew.getX() == oLast.getX() &&
     558           0 :             oFirstNew.getY() == oLast.getY())
     559             :         {
     560           0 :             PointList oList;
     561           0 :             FillPointList(&oList, poLine);
     562             :             /* forward, skip first point */
     563           0 :             ring->insert(ring->end(), oList.begin() + 1, oList.end());
     564           0 :             return true;
     565             :         }
     566             : 
     567           0 :         if (bBackward && oFirstNew.getX() == oFirst.getX() &&
     568           0 :             oFirstNew.getY() == oFirst.getY())
     569             :         {
     570           0 :             PointList oList;
     571           0 :             FillPointList(&oList, poLine);
     572             :             /* backward, skip last point */
     573           0 :             ring->insert(ring->begin(), oList.rbegin(), oList.rend() - 1);
     574           0 :             return true;
     575             :         }
     576             : 
     577           0 :         if (oLastNew.getX() == oLast.getX() && oLastNew.getY() == oLast.getY())
     578             :         {
     579           0 :             PointList oList;
     580           0 :             FillPointList(&oList, poLine);
     581             :             /* backward, skip first point */
     582           0 :             ring->insert(ring->end(), oList.rbegin() + 1, oList.rend());
     583           0 :             return true;
     584             :         }
     585             : 
     586           0 :         if (bBackward && oLastNew.getX() == oFirst.getX() &&
     587           0 :             oLastNew.getY() == oFirst.getY())
     588             :         {
     589           0 :             PointList oList;
     590           0 :             FillPointList(&oList, poLine);
     591             :             /* forward, skip last point */
     592           0 :             ring->insert(ring->begin(), oList.begin(), oList.end() - 1);
     593           0 :             return true;
     594             :         }
     595             :     }
     596             : 
     597           0 :     return false;
     598             : }
     599             : 
     600             : /*!
     601             :   \brief Set next feature
     602             : 
     603             :   \param poFeature pointer to current feature
     604             : 
     605             :   \return index of current feature or -1 on failure
     606             : */
     607           0 : int IVFKDataBlock::SetNextFeature(const IVFKFeature *poFeature)
     608             : {
     609           0 :     for (int i = 0; i < m_nFeatureCount; i++)
     610             :     {
     611           0 :         if (m_papoFeature[i] == poFeature)
     612             :         {
     613           0 :             m_iNextFeature = i + 1;
     614           0 :             return i;
     615             :         }
     616             :     }
     617             : 
     618           0 :     return -1;
     619             : }
     620             : 
     621             : /*!
     622             :   \brief Add feature
     623             : 
     624             :   \param poNewFeature pointer to VFKFeature instance
     625             : */
     626         969 : void IVFKDataBlock::AddFeature(IVFKFeature *poNewFeature)
     627             : {
     628         969 :     m_nFeatureCount++;
     629             : 
     630        1938 :     m_papoFeature = (IVFKFeature **)CPLRealloc(
     631         969 :         m_papoFeature, sizeof(IVFKFeature *) * m_nFeatureCount);
     632         969 :     m_papoFeature[m_nFeatureCount - 1] = poNewFeature;
     633         969 : }
     634             : 
     635             : /*!
     636             :   \brief Get number of records
     637             : 
     638             :   \param iRec record type (valid, skipped, duplicated)
     639             : 
     640             :   \return number of records
     641             : */
     642        4816 : int IVFKDataBlock::GetRecordCount(RecordType iRec) const
     643             : {
     644        4816 :     return (int)m_nRecordCount[iRec];
     645             : }
     646             : 
     647             : /*!
     648             :   \brief Increment number of records
     649             : 
     650             :   \param iRec record type (valid, skipped, duplicated)
     651             : */
     652        1152 : void IVFKDataBlock::SetIncRecordCount(RecordType iRec)
     653             : {
     654        1152 :     m_nRecordCount[iRec]++;
     655        1152 : }
     656             : 
     657             : /*!
     658             :   \brief Get first found feature based on its properties
     659             : 
     660             :   Note: modifies next feature.
     661             : 
     662             :   \param idx property index
     663             :   \param value property value
     664             :   \param poList list of features (NULL to loop all features)
     665             : 
     666             :   \return pointer to feature definition or NULL on failure (not found)
     667             : */
     668           0 : VFKFeature *VFKDataBlock::GetFeature(int idx, GUIntBig value,
     669             :                                      VFKFeatureList *poList)
     670             : {
     671           0 :     if (poList)
     672             :     {
     673           0 :         for (VFKFeatureList::iterator i = poList->begin(), e = poList->end();
     674           0 :              i != e; ++i)
     675             :         {
     676           0 :             VFKFeature *poVfkFeature = *i;
     677           0 :             const GUIntBig iPropertyValue = strtoul(
     678             :                 poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
     679           0 :             if (iPropertyValue == value)
     680             :             {
     681           0 :                 poList->erase(i); /* ??? */
     682           0 :                 return poVfkFeature;
     683             :             }
     684             :         }
     685             :     }
     686             :     else
     687             :     {
     688           0 :         for (int i = 0; i < m_nFeatureCount; i++)
     689             :         {
     690             :             VFKFeature *poVfkFeature =
     691           0 :                 cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
     692           0 :             const GUIntBig iPropertyValue = strtoul(
     693             :                 poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
     694           0 :             if (iPropertyValue == value)
     695             :             {
     696           0 :                 m_iNextFeature = i + 1;
     697           0 :                 return poVfkFeature;
     698             :             }
     699             :         }
     700             :     }
     701             : 
     702           0 :     return nullptr;
     703             : }
     704             : 
     705             : /*!
     706             :   \brief Get features based on properties
     707             : 
     708             :   \param idx property index
     709             :   \param value property value
     710             : 
     711             :   \return list of features
     712             : */
     713           0 : VFKFeatureList VFKDataBlock::GetFeatures(int idx, GUIntBig value)
     714             : {
     715           0 :     std::vector<VFKFeature *> poResult;
     716             : 
     717           0 :     for (int i = 0; i < m_nFeatureCount; i++)
     718             :     {
     719             :         VFKFeature *poVfkFeature =
     720           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
     721             :         const GUIntBig iPropertyValue =
     722           0 :             strtoul(poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
     723           0 :         if (iPropertyValue == value)
     724             :         {
     725           0 :             poResult.push_back(poVfkFeature);
     726             :         }
     727             :     }
     728             : 
     729           0 :     return poResult;
     730             : }
     731             : 
     732             : /*!
     733             :   \brief Get features based on properties
     734             : 
     735             :   \param idx1 property index
     736             :   \param idx2 property index
     737             :   \param value property value
     738             : 
     739             :   \return list of features
     740             : */
     741           0 : VFKFeatureList VFKDataBlock::GetFeatures(int idx1, int idx2, GUIntBig value)
     742             : {
     743           0 :     std::vector<VFKFeature *> poResult;
     744             : 
     745           0 :     for (int i = 0; i < m_nFeatureCount; i++)
     746             :     {
     747             :         VFKFeature *poVfkFeature =
     748           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
     749             :         const GUIntBig iPropertyValue1 =
     750           0 :             strtoul(poVfkFeature->GetProperty(idx1)->GetValueS(), nullptr, 0);
     751           0 :         if (idx2 < 0)
     752             :         {
     753           0 :             if (iPropertyValue1 == value)
     754             :             {
     755           0 :                 poResult.push_back(poVfkFeature);
     756             :             }
     757             :         }
     758             :         else
     759             :         {
     760           0 :             const GUIntBig iPropertyValue2 = strtoul(
     761             :                 poVfkFeature->GetProperty(idx2)->GetValueS(), nullptr, 0);
     762           0 :             if (iPropertyValue1 == value || iPropertyValue2 == value)
     763             :             {
     764           0 :                 poResult.push_back(poVfkFeature);
     765             :             }
     766             :         }
     767             :     }
     768             : 
     769           0 :     return poResult;
     770             : }
     771             : 
     772             : /*!
     773             :   \brief Get feature count based on property value
     774             : 
     775             :   \param pszName property name
     776             :   \param pszValue property value
     777             : 
     778             :   \return number of features or -1 on error
     779             : */
     780           0 : GIntBig VFKDataBlock::GetFeatureCount(const char *pszName, const char *pszValue)
     781             : {
     782           0 :     const int propIdx = GetPropertyIndex(pszName);
     783           0 :     if (propIdx < 0)
     784           0 :         return -1;
     785             : 
     786           0 :     int nfeatures = 0;
     787           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
     788             :     {
     789           0 :         VFKFeature *poVFKFeature = cpl::down_cast<VFKFeature *>(
     790             :             ((IVFKDataBlock *)this)->GetFeature(i));
     791           0 :         if (!poVFKFeature)
     792           0 :             return -1;
     793           0 :         if (EQUAL(poVFKFeature->GetProperty(propIdx)->GetValueS(), pszValue))
     794           0 :             nfeatures++;
     795             :     }
     796             : 
     797           0 :     return nfeatures;
     798             : }
     799             : 
     800             : /*!
     801             :   \brief Load geometry (point layers)
     802             : 
     803             :   \return number of invalid features
     804             : */
     805           0 : int VFKDataBlock::LoadGeometryPoint()
     806             : {
     807           0 :     int nInvalid = 0;
     808           0 :     int i_idxY = GetPropertyIndex("SOURADNICE_Y");
     809           0 :     int i_idxX = GetPropertyIndex("SOURADNICE_X");
     810           0 :     if (i_idxY < 0 || i_idxX < 0)
     811             :     {
     812           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     813             :                  m_pszName);
     814           0 :         return nInvalid;
     815             :     }
     816             : 
     817           0 :     for (int j = 0; j < ((IVFKDataBlock *)this)->GetFeatureCount(); j++)
     818             :     {
     819             :         VFKFeature *poFeature =
     820           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(j));
     821           0 :         double x = -1.0 * poFeature->GetProperty(i_idxY)->GetValueD();
     822           0 :         double y = -1.0 * poFeature->GetProperty(i_idxX)->GetValueD();
     823           0 :         OGRPoint pt(x, y);
     824           0 :         if (!poFeature->SetGeometry(&pt))
     825           0 :             nInvalid++;
     826             :     }
     827             : 
     828           0 :     return nInvalid;
     829             : }
     830             : 
     831             : /*!
     832             :   \brief Load geometry (linestring SBP/SBPG layer)
     833             : 
     834             :   \return number of invalid features
     835             : */
     836           0 : int VFKDataBlock::LoadGeometryLineStringSBP()
     837             : {
     838             :     VFKDataBlock *poDataBlockPoints =
     839           0 :         cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SOBR"));
     840           0 :     if (nullptr == poDataBlockPoints)
     841             :     {
     842           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     843             :                  m_pszName);
     844           0 :         return 0;
     845             :     }
     846             : 
     847           0 :     poDataBlockPoints->LoadGeometry();
     848           0 :     int idxId = poDataBlockPoints->GetPropertyIndex("ID");
     849           0 :     int idxBp_Id = GetPropertyIndex("BP_ID");
     850           0 :     int idxPCB = GetPropertyIndex("PORADOVE_CISLO_BODU");
     851           0 :     if (idxId < 0 || idxBp_Id < 0 || idxPCB < 0)
     852             :     {
     853           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     854             :                  m_pszName);
     855           0 :         return 0;
     856             :     }
     857             : 
     858           0 :     OGRLineString oOGRLine;
     859           0 :     VFKFeature *poLine = nullptr;
     860           0 :     int nInvalid = 0;
     861             : 
     862           0 :     for (int j = 0; j < ((IVFKDataBlock *)this)->GetFeatureCount(); j++)
     863             :     {
     864             :         VFKFeature *poFeature =
     865           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(j));
     866           0 :         CPLAssert(nullptr != poFeature);
     867             : 
     868           0 :         poFeature->SetGeometry(nullptr);
     869             :         GUIntBig id =
     870           0 :             strtoul(poFeature->GetProperty(idxBp_Id)->GetValueS(), nullptr, 0);
     871             :         GUIntBig ipcb =
     872           0 :             strtoul(poFeature->GetProperty(idxPCB)->GetValueS(), nullptr, 0);
     873           0 :         if (ipcb == 1)
     874             :         {
     875           0 :             if (!oOGRLine.IsEmpty())
     876             :             {
     877           0 :                 oOGRLine.setCoordinateDimension(2); /* force 2D */
     878           0 :                 if (poLine != nullptr && !poLine->SetGeometry(&oOGRLine))
     879           0 :                     nInvalid++;
     880           0 :                 oOGRLine.empty(); /* restore line */
     881             :             }
     882           0 :             poLine = poFeature;
     883             :         }
     884             :         else
     885             :         {
     886           0 :             poFeature->SetGeometryType(wkbUnknown);
     887             :         }
     888           0 :         VFKFeature *poPoint = poDataBlockPoints->GetFeature(idxId, id);
     889           0 :         if (!poPoint)
     890           0 :             continue;
     891           0 :         const OGRPoint *pt = poPoint->GetGeometry()->toPoint();
     892           0 :         oOGRLine.addPoint(pt);
     893             :     }
     894             :     /* add last line */
     895           0 :     oOGRLine.setCoordinateDimension(2); /* force 2D */
     896           0 :     if (poLine)
     897             :     {
     898           0 :         if (!poLine->SetGeometry(&oOGRLine))
     899           0 :             nInvalid++;
     900             :     }
     901           0 :     poDataBlockPoints->ResetReading();
     902             : 
     903           0 :     return nInvalid;
     904             : }
     905             : 
     906             : /*!
     907             :   \brief Load geometry (linestring HP/DPM/ZVB layer)
     908             : 
     909             :   \return number of invalid features
     910             : */
     911           0 : int VFKDataBlock::LoadGeometryLineStringHP()
     912             : {
     913           0 :     int nInvalid = 0;
     914             : 
     915             :     VFKDataBlock *poDataBlockLines =
     916           0 :         cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SBP"));
     917           0 :     if (nullptr == poDataBlockLines)
     918             :     {
     919           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     920             :                  m_pszName);
     921           0 :         return nInvalid;
     922             :     }
     923             : 
     924           0 :     poDataBlockLines->LoadGeometry();
     925           0 :     const int idxId = GetPropertyIndex("ID");
     926           0 :     CPLString osColumn;
     927           0 :     osColumn.Printf("%s_ID", m_pszName);
     928           0 :     const int idxMy_Id = poDataBlockLines->GetPropertyIndex(osColumn);
     929             :     const int idxPCB =
     930           0 :         poDataBlockLines->GetPropertyIndex("PORADOVE_CISLO_BODU");
     931           0 :     if (idxId < 0 || idxMy_Id < 0 || idxPCB < 0)
     932             :     {
     933           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
     934             :                  m_pszName);
     935           0 :         return nInvalid;
     936             :     }
     937             : 
     938             :     // Reduce to first segment.
     939           0 :     VFKFeatureList poLineList = poDataBlockLines->GetFeatures(idxPCB, 1);
     940           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
     941             :     {
     942             :         VFKFeature *poFeature =
     943           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
     944           0 :         CPLAssert(nullptr != poFeature);
     945             :         GUIntBig id =
     946           0 :             strtoul(poFeature->GetProperty(idxId)->GetValueS(), nullptr, 0);
     947             :         VFKFeature *poLine =
     948           0 :             poDataBlockLines->GetFeature(idxMy_Id, id, &poLineList);
     949           0 :         if (!poLine || !poLine->GetGeometry())
     950           0 :             continue;
     951           0 :         if (!poFeature->SetGeometry(poLine->GetGeometry()))
     952           0 :             nInvalid++;
     953             :     }
     954           0 :     poDataBlockLines->ResetReading();
     955             : 
     956           0 :     return nInvalid;
     957             : }
     958             : 
     959             : /*!
     960             :   \brief Load geometry (polygon BUD/PAR layers)
     961             : 
     962             :   \return number of invalid features
     963             : */
     964           0 : int VFKDataBlock::LoadGeometryPolygon()
     965             : {
     966           0 :     VFKDataBlock *poDataBlockLines1 = nullptr;
     967           0 :     VFKDataBlock *poDataBlockLines2 = nullptr;
     968             : 
     969           0 :     bool bIsPar = false;
     970           0 :     if (EQUAL(m_pszName, "PAR"))
     971             :     {
     972             :         poDataBlockLines1 =
     973           0 :             cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("HP"));
     974           0 :         poDataBlockLines2 = poDataBlockLines1;
     975           0 :         bIsPar = true;
     976             :     }
     977             :     else
     978             :     {
     979             :         poDataBlockLines1 =
     980           0 :             cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("OB"));
     981             :         poDataBlockLines2 =
     982           0 :             cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SBP"));
     983           0 :         bIsPar = false;
     984             :     }
     985             : 
     986           0 :     int nInvalid = 0;
     987           0 :     if (nullptr == poDataBlockLines1 || nullptr == poDataBlockLines2)
     988             :     {
     989           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
     990             :                  m_pszName);
     991           0 :         return nInvalid;
     992             :     }
     993             : 
     994           0 :     poDataBlockLines1->LoadGeometry();
     995           0 :     poDataBlockLines2->LoadGeometry();
     996           0 :     int idxId = GetPropertyIndex("ID");
     997           0 :     if (idxId < 0)
     998             :     {
     999           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
    1000             :                  m_pszName);
    1001           0 :         return nInvalid;
    1002             :     }
    1003             : 
    1004           0 :     int idxBud = 0;
    1005           0 :     int idxOb = 0;
    1006           0 :     int idxIdOb = 0;
    1007           0 :     int idxPar1 = 0;
    1008           0 :     int idxPar2 = 0;
    1009           0 :     if (bIsPar)
    1010             :     {
    1011           0 :         idxPar1 = poDataBlockLines1->GetPropertyIndex("PAR_ID_1");
    1012           0 :         idxPar2 = poDataBlockLines1->GetPropertyIndex("PAR_ID_2");
    1013           0 :         if (idxPar1 < 0 || idxPar2 < 0)
    1014             :         {
    1015           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
    1016             :                      m_pszName);
    1017           0 :             return nInvalid;
    1018             :         }
    1019             :     }
    1020             :     else
    1021             :     { /* BUD */
    1022           0 :         idxIdOb = poDataBlockLines1->GetPropertyIndex("ID");
    1023           0 :         idxBud = poDataBlockLines1->GetPropertyIndex("BUD_ID");
    1024           0 :         idxOb = poDataBlockLines2->GetPropertyIndex("OB_ID");
    1025           0 :         if (idxIdOb < 0 || idxBud < 0 || idxOb < 0)
    1026             :         {
    1027           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
    1028             :                      m_pszName);
    1029           0 :             return nInvalid;
    1030             :         }
    1031             :     }
    1032             : 
    1033           0 :     VFKFeatureList poLineList;
    1034           0 :     PointListArray poRingList; /* first is to be considered as exterior */
    1035           0 :     OGRLinearRing ogrRing;
    1036           0 :     OGRPolygon ogrPolygon;
    1037             : 
    1038           0 :     for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
    1039             :     {
    1040             :         VFKFeature *poFeature =
    1041           0 :             cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
    1042           0 :         CPLAssert(nullptr != poFeature);
    1043             :         const GUIntBig id =
    1044           0 :             strtoul(poFeature->GetProperty(idxId)->GetValueS(), nullptr, 0);
    1045           0 :         if (bIsPar)
    1046             :         {
    1047           0 :             poLineList = poDataBlockLines1->GetFeatures(idxPar1, idxPar2, id);
    1048             :         }
    1049             :         else
    1050             :         {
    1051             :             VFKFeature *poLineOb, *poLineSbp;
    1052           0 :             std::vector<VFKFeature *> poLineListOb;
    1053           0 :             poLineListOb = poDataBlockLines1->GetFeatures(idxBud, id);
    1054           0 :             for (std::vector<VFKFeature *>::const_iterator
    1055           0 :                      iOb = poLineListOb.begin(),
    1056           0 :                      eOb = poLineListOb.end();
    1057           0 :                  iOb != eOb; ++iOb)
    1058             :             {
    1059           0 :                 poLineOb = (*iOb);
    1060           0 :                 GUIntBig idOb = strtoul(
    1061             :                     poLineOb->GetProperty(idxIdOb)->GetValueS(), nullptr, 0);
    1062           0 :                 poLineSbp = poDataBlockLines2->GetFeature(idxOb, idOb);
    1063           0 :                 if (poLineSbp)
    1064           0 :                     poLineList.push_back(poLineSbp);
    1065             :             }
    1066             :         }
    1067           0 :         if (poLineList.size() < 1)
    1068           0 :             continue;
    1069             : 
    1070             :         /* clear */
    1071           0 :         ogrPolygon.empty();
    1072           0 :         poRingList.clear();
    1073             : 
    1074             :         /* collect rings (points) */
    1075           0 :         bool bFound = false;
    1076           0 :         int nCount = 0;
    1077           0 :         int nCountMax = static_cast<int>(poLineList.size()) * 2;
    1078           0 :         while (!poLineList.empty() && nCount < nCountMax)
    1079             :         {
    1080           0 :             bool bNewRing = !bFound;
    1081           0 :             bFound = false;
    1082           0 :             for (VFKFeatureList::iterator iHp = poLineList.begin(),
    1083           0 :                                           eHp = poLineList.end();
    1084           0 :                  iHp != eHp; ++iHp)
    1085             :             {
    1086           0 :                 auto pGeom = (*iHp)->GetGeometry();
    1087           0 :                 if (pGeom && AppendLineToRing(&poRingList,
    1088             :                                               pGeom->toLineString(), bNewRing))
    1089             :                 {
    1090           0 :                     bFound = true;
    1091           0 :                     poLineList.erase(iHp);
    1092           0 :                     break;
    1093             :                 }
    1094             :             }
    1095           0 :             nCount++;
    1096             :         }
    1097             :         /* create rings */
    1098           0 :         for (PointListArray::const_iterator iRing = poRingList.begin(),
    1099           0 :                                             eRing = poRingList.end();
    1100           0 :              iRing != eRing; ++iRing)
    1101             :         {
    1102           0 :             PointList *poList = *iRing;
    1103           0 :             ogrRing.empty();
    1104           0 :             for (PointList::iterator iPoint = poList->begin(),
    1105           0 :                                      ePoint = poList->end();
    1106           0 :                  iPoint != ePoint; ++iPoint)
    1107             :             {
    1108           0 :                 ogrRing.addPoint(&(*iPoint));
    1109             :             }
    1110           0 :             ogrPolygon.addRing(&ogrRing);
    1111             :         }
    1112             :         /* set polygon */
    1113           0 :         ogrPolygon.setCoordinateDimension(2); /* force 2D */
    1114           0 :         if (!poFeature->SetGeometry(&ogrPolygon))
    1115           0 :             nInvalid++;
    1116             :     }
    1117             : 
    1118             :     /* free ring list */
    1119           0 :     for (PointListArray::iterator iRing = poRingList.begin(),
    1120           0 :                                   eRing = poRingList.end();
    1121           0 :          iRing != eRing; ++iRing)
    1122             :     {
    1123           0 :         delete (*iRing);
    1124           0 :         *iRing = nullptr;
    1125             :     }
    1126           0 :     poDataBlockLines1->ResetReading();
    1127           0 :     poDataBlockLines2->ResetReading();
    1128             : 
    1129           0 :     return nInvalid;
    1130             : }

Generated by: LCOV version 1.14