LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vfk - vfkfeature.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 173 395 43.8 %
Date: 2024-05-04 12:52:34 Functions: 9 21 42.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  VFK Reader - Feature definition
       4             :  * Purpose:  Implements IVFKFeature/VFKFeature class.
       5             :  * Author:   Martin Landa, landa.martin gmail.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009-2010, 2012-2015, Martin Landa <landa.martin gmail.com>
       9             :  * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person
      12             :  * obtaining a copy of this software and associated documentation
      13             :  * files (the "Software"), to deal in the Software without
      14             :  * restriction, including without limitation the rights to use, copy,
      15             :  * modify, merge, publish, distribute, sublicense, and/or sell copies
      16             :  * of the Software, and to permit persons to whom the Software is
      17             :  * furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be
      20             :  * included in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      23             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      24             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      25             :  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
      26             :  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
      27             :  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
      28             :  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      29             :  * SOFTWARE.
      30             :  ****************************************************************************/
      31             : 
      32             : #include "vfkreader.h"
      33             : #include "vfkreaderp.h"
      34             : 
      35             : #include "cpl_conv.h"
      36             : #include "cpl_error.h"
      37             : 
      38             : /*!
      39             :   \brief IVFKFeature constructor
      40             : 
      41             :   \param poDataBlock pointer to VFKDataBlock instance
      42             : */
      43        1558 : IVFKFeature::IVFKFeature(IVFKDataBlock *poDataBlock)
      44             :     : m_poDataBlock(poDataBlock), m_nFID(-1),
      45        3116 :       m_nGeometryType(poDataBlock->GetGeometryType()), m_bGeometry(false),
      46        1558 :       m_bValid(false)
      47             : {
      48        1558 :     CPLAssert(nullptr != poDataBlock);
      49        1558 : }
      50             : 
      51             : /*!
      52             :   \brief IVFKFeature destructor
      53             : */
      54        3116 : IVFKFeature::~IVFKFeature()
      55             : {
      56        1558 :     m_poDataBlock = nullptr;
      57        1558 : }
      58             : 
      59             : /*!
      60             :   \brief Set feature geometry type
      61             : */
      62           0 : void IVFKFeature::SetGeometryType(OGRwkbGeometryType nGeomType)
      63             : {
      64           0 :     m_nGeometryType = nGeomType;
      65           0 : }
      66             : 
      67             : /*!
      68             :   \brief Set feature id
      69             : 
      70             :   FID: 0 for next, -1 for same
      71             : 
      72             :   \param nFID feature id
      73             : */
      74           0 : void IVFKFeature::SetFID(GIntBig nFID)
      75             : {
      76           0 :     if (m_nFID > 0)
      77             :     {
      78           0 :         m_nFID = nFID;
      79             :     }
      80             :     else
      81             :     {
      82           0 :         m_nFID = m_poDataBlock->GetFeatureCount() + 1;
      83             :     }
      84           0 : }
      85             : 
      86             : /*!
      87             :   \brief Compute determinant of matrix with columns x,y and z
      88             : 
      89             :   Simple formula requires reasonable numbers
      90             : 
      91             :   \param x first column array
      92             :   \param y second column array
      93             :   \param z third column array
      94             : 
      95             :   \return double determinant value
      96             : */
      97           0 : double IVFKFeature::GetDeterminatOfMatrixDim3(double x[3], double y[3],
      98             :                                               double z[3])
      99             : {
     100           0 :     return x[0] * y[1] * z[2] - x[0] * z[1] * y[2] - y[0] * x[1] * z[2] +
     101           0 :            y[0] * x[2] * z[1] + z[0] * x[1] * y[2] - z[0] * y[1] * x[2];
     102             : }
     103             : 
     104             : /*!
     105             :   \brief Find circle center determined by three point
     106             : 
     107             :   \param c_xy circle center coordinates array
     108             :   \param x array of three x coordinates
     109             :   \param y array of three x coordinates
     110             : */
     111           0 : void IVFKFeature::GetCircleCenterFrom3Points(double c_xy[2], double x[3],
     112             :                                              double y[3])
     113             : {
     114             :     /* reduce coordinates by average coordinate */
     115           0 :     int n = 3;
     116           0 :     double sum_x = 0.0f, sum_y = 0.0f;
     117           0 :     for (int i = 0; i < n; i++)
     118             :     {
     119           0 :         sum_x += x[i];
     120           0 :         sum_y += y[i];
     121             :     }
     122             : 
     123           0 :     const double x_t = sum_x / 3;
     124           0 :     const double y_t = sum_y / 3;
     125             : 
     126             :     double x_r[3], y_r[3];
     127             : 
     128           0 :     for (int i = 0; i < n; i++)
     129             :     {
     130           0 :         x_r[i] = x[i] - x_t;
     131           0 :         y_r[i] = y[i] - y_t;
     132             :     }
     133             : 
     134             :     /* limits to test reasonable value of determinant */
     135           0 :     const double epsilon_min = 0.0001;
     136           0 :     const double epsilon_max = 10000e6;
     137             : 
     138             :     /* solve three linear equations */
     139           0 :     double z[3] = {1.0, 1.0, 1.0};
     140           0 :     double c[3] = {-(pow(x_r[0], 2) + pow(y_r[0], 2)),
     141           0 :                    -(pow(x_r[1], 2) + pow(y_r[1], 2)),
     142           0 :                    -(pow(x_r[2], 2) + pow(y_r[2], 2))};
     143           0 :     const double det_A = GetDeterminatOfMatrixDim3(x_r, y_r, z);
     144             : 
     145           0 :     if (epsilon_min <= std::fabs(det_A) && std::fabs(det_A) <= epsilon_max)
     146             :     {
     147           0 :         const double det_a = GetDeterminatOfMatrixDim3(c, y_r, z);
     148           0 :         const double det_b = GetDeterminatOfMatrixDim3(x_r, c, z);
     149           0 :         c_xy[0] = -det_a / det_A / 2 + x_t;
     150           0 :         c_xy[1] = -det_b / det_A / 2 + y_t;
     151             :     }
     152             :     else
     153             :     {
     154           0 :         c_xy[0] = -1.0;
     155           0 :         c_xy[1] = -1.0;
     156             :     }
     157           0 : }
     158             : 
     159             : /*!
     160             :   \brief Add points to circle geometry
     161             : 
     162             :   \param poGeomString pointer to OGRCircularString
     163             :   \param c_x circle center x coordinate
     164             :   \param c_y circle center y coordinate
     165             :   \param r circle radius
     166             : */
     167           0 : void IVFKFeature::AddCirclePointsToGeomString(OGRCircularString &poGeomString,
     168             :                                               double c_x, double c_y, double r)
     169             : {
     170           0 :     OGRPoint pt;
     171             : 
     172             :     /* define first point on a circle */
     173           0 :     pt.setX(c_x + r);
     174           0 :     pt.setY(c_y);
     175           0 :     poGeomString.addPoint(&pt);
     176             : 
     177             :     /* define second point on a circle */
     178           0 :     pt.setX(c_x);
     179           0 :     pt.setY(c_y + r);
     180           0 :     poGeomString.addPoint(&pt);
     181             : 
     182             :     /* define third point on a circle */
     183           0 :     pt.setX(c_x - r);
     184           0 :     pt.setY(c_y);
     185           0 :     poGeomString.addPoint(&pt);
     186             : 
     187             :     /* define fourth point on a circle */
     188           0 :     pt.setX(c_x);
     189           0 :     pt.setY(c_y - r);
     190           0 :     poGeomString.addPoint(&pt);
     191             : 
     192             :     /* define last point (=first) on a circle */
     193           0 :     pt.setX(c_x + r);
     194           0 :     pt.setY(c_y);
     195           0 :     poGeomString.addPoint(&pt);
     196           0 : }
     197             : 
     198             : /*!
     199             :   \brief Set feature geometry
     200             : 
     201             :   Also checks if given geometry is valid
     202             : 
     203             :   \param poGeom pointer to OGRGeometry
     204             :   \param ftype geometry VFK type
     205             : 
     206             :   \return true on valid feature or otherwise false
     207             : */
     208         615 : bool IVFKFeature::SetGeometry(const OGRGeometry *poGeom, const char *ftype)
     209             : {
     210         615 :     m_bGeometry = true;
     211             : 
     212         615 :     m_bValid = true;
     213             : 
     214         615 :     if (!poGeom)
     215             :     {
     216           0 :         return m_bValid;
     217             :     }
     218             : 
     219             :     /* check empty geometries */
     220         615 :     if (m_nGeometryType == wkbNone && poGeom->IsEmpty())
     221             :     {
     222           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     223             :                  "%s: empty geometry fid = " CPL_FRMT_GIB,
     224           0 :                  m_poDataBlock->GetName(), m_nFID);
     225           0 :         m_bValid = false;
     226             :     }
     227             : 
     228             :     /* check coordinates */
     229         615 :     if (m_nGeometryType == wkbPoint)
     230             :     {
     231         195 :         auto poPoint = poGeom->toPoint();
     232         195 :         const double x = poPoint->getX();
     233         195 :         const double y = poPoint->getY();
     234         195 :         if (x > -430000 || x < -910000 || y > -930000 || y < -1230000)
     235             :         {
     236           0 :             CPLDebug("OGR-VFK", "%s: invalid point fid = " CPL_FRMT_GIB,
     237           0 :                      m_poDataBlock->GetName(), m_nFID);
     238           0 :             m_bValid = false;
     239             :         }
     240             :     }
     241             : 
     242             :     /* check degenerated polygons */
     243         615 :     if (m_nGeometryType == wkbPolygon)
     244             :     {
     245          15 :         const OGRLinearRing *poRing = poGeom->toPolygon()->getExteriorRing();
     246          15 :         if (!poRing || poRing->getNumPoints() < 3)
     247             :         {
     248           0 :             CPLDebug("OGR-VFK", "%s: invalid polygon fid = " CPL_FRMT_GIB,
     249           0 :                      m_poDataBlock->GetName(), m_nFID);
     250           0 :             m_bValid = false;
     251             :         }
     252             :     }
     253             : 
     254         615 :     std::unique_ptr<OGRGeometry> newGeom;
     255         615 :     if (m_bValid)
     256             :     {
     257         615 :         if (ftype)
     258             :         {
     259         196 :             OGRPoint pt;
     260         196 :             OGRCircularString poGeomString;
     261             : 
     262         196 :             OGRGeometry *poGeomCurved = nullptr;
     263         196 :             if (EQUAL(ftype, "15") || EQUAL(ftype, "16"))
     264             :             { /* -> circle or arc */
     265          14 :                 auto poLS = poGeom->toLineString();
     266          14 :                 const int npoints = poLS->getNumPoints();
     267          14 :                 if (!EQUAL(ftype, "15"))
     268             :                 {
     269          56 :                     for (int i = 0; i < npoints; i++)
     270             :                     {
     271          42 :                         poLS->getPoint(i, &pt);
     272          42 :                         poGeomString.addPoint(&pt);
     273             :                     }
     274             :                 }
     275          14 :                 if (EQUAL(ftype, "15"))
     276             :                 {
     277           0 :                     if (npoints < 3)
     278             :                     {
     279           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     280             :                                  "npoints is %d.  expected 3", npoints);
     281             :                     }
     282           0 :                     if (npoints > 3)
     283             :                     {
     284           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     285             :                                  "npoints is %d.  Will overflow buffers.  "
     286             :                                  "Cannot continue.",
     287             :                                  npoints);
     288           0 :                         m_bValid = false;
     289           0 :                         return false;
     290             :                     }
     291             : 
     292             :                     /* compute center and radius of a circle */
     293           0 :                     double x[3] = {0.0, 0.0, 0.0};
     294           0 :                     double y[3] = {0.0, 0.0, 0.0};
     295             : 
     296           0 :                     for (int i = 0; i < npoints; i++)
     297             :                     {
     298           0 :                         poLS->getPoint(i, &pt);
     299           0 :                         x[i] = pt.getX();
     300           0 :                         y[i] = pt.getY();
     301             :                     }
     302             : 
     303             :                     /* solve as 3 linear equation x^2+y^2+2ax+2by+c=0 */
     304             :                     double c_xy[2];
     305           0 :                     double r = 0.0f;
     306           0 :                     GetCircleCenterFrom3Points(c_xy, x, y);
     307             : 
     308             :                     /* TODO (seidlmic) how to correctly handle invalid configuration */
     309           0 :                     if (c_xy[0] == -1.0f && c_xy[1] == -1.0f)
     310             :                     {
     311           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     312             :                                  "Invalid 3 points circle configuration. Can "
     313             :                                  "not find circle center");
     314           0 :                         m_bValid = false;
     315           0 :                         return false;
     316             :                     }
     317             : 
     318           0 :                     r = pow(pow((c_xy[0] - x[0]), 2) + pow((c_xy[1] - y[0]), 2),
     319             :                             0.5);
     320             : 
     321           0 :                     CPLDebug(
     322             :                         "OGR-VFK",
     323             :                         "Circle center point (ftype 15) X: %f, Y: %f, r: %f",
     324             :                         c_xy[0], c_xy[1], r);
     325             : 
     326           0 :                     AddCirclePointsToGeomString(poGeomString, c_xy[0], c_xy[1],
     327             :                                                 r);
     328          14 :                 }
     329             :             }
     330         182 :             else if (strlen(ftype) > 2 && STARTS_WITH_CI(ftype, "15"))
     331             :             {                   /* -> circle with radius */
     332           0 :                 char s[3] = {}; /* 15 */
     333             : 
     334           0 :                 float r = 0.0f;
     335           0 :                 if (2 != sscanf(ftype, "%2s %f", s, &r) || r < 0)
     336             :                 {
     337           0 :                     CPLDebug("OGR-VFK",
     338             :                              "%s: invalid circle (unknown or negative radius) "
     339             :                              "fid = " CPL_FRMT_GIB,
     340           0 :                              m_poDataBlock->GetName(), m_nFID);
     341           0 :                     m_bValid = false;
     342             :                 }
     343             :                 else
     344             :                 {
     345           0 :                     auto poLS = poGeom->toLineString();
     346           0 :                     poLS->getPoint(0, &pt);
     347           0 :                     const double c_x = pt.getX();
     348           0 :                     const double c_y = pt.getY();
     349             : 
     350           0 :                     AddCirclePointsToGeomString(poGeomString, c_x, c_y, r);
     351           0 :                 }
     352             :             }
     353         182 :             else if (EQUAL(ftype, "11"))
     354             :             { /* curve */
     355           0 :                 auto poLS = poGeom->toLineString();
     356           0 :                 const int npoints = poLS->getNumPoints();
     357           0 :                 if (npoints > 2)
     358             :                 { /* circular otherwise line string */
     359           0 :                     for (int i = 0; i < npoints; i++)
     360             :                     {
     361           0 :                         poLS->getPoint(i, &pt);
     362           0 :                         poGeomString.addPoint(&pt);
     363             :                     }
     364             :                 }
     365             :             }
     366             : 
     367         196 :             if (!poGeomString.IsEmpty())
     368          14 :                 poGeomCurved = poGeomString.CurveToLine();
     369             : 
     370         196 :             if (poGeomCurved)
     371             :             {
     372             :                 const int npoints =
     373          14 :                     poGeomCurved->toLineString()->getNumPoints();
     374          14 :                 CPLDebug("OGR-VFK",
     375             :                          "%s: curve (type=%s) to linestring (npoints=%d) fid "
     376             :                          "= " CPL_FRMT_GIB,
     377          14 :                          m_poDataBlock->GetName(), ftype, npoints, m_nFID);
     378          14 :                 if (npoints > 1)
     379          14 :                     newGeom.reset(poGeomCurved->clone());
     380          14 :                 delete poGeomCurved;
     381             :             }
     382             :         }
     383             : 
     384         615 :         if (!newGeom)
     385             :         {
     386             :             /* check degenerated linestrings */
     387         601 :             if (m_nGeometryType == wkbLineString)
     388             :             {
     389         391 :                 auto poLS = poGeom->toLineString();
     390         391 :                 const int npoints = poLS->getNumPoints();
     391         391 :                 if (npoints < 2)
     392             :                 {
     393           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     394             :                              "%s: invalid linestring (%d vertices) fid "
     395             :                              "= " CPL_FRMT_GIB,
     396           0 :                              m_poDataBlock->GetName(), npoints, m_nFID);
     397           0 :                     m_bValid = false;
     398             :                 }
     399             :             }
     400             : 
     401         601 :             if (m_bValid)
     402         601 :                 newGeom.reset(poGeom->clone()); /* make copy */
     403             :         }
     404             :     }
     405             : 
     406         615 :     m_paGeom = std::move(newGeom);
     407             : 
     408         615 :     return m_bValid;
     409             : }
     410             : 
     411             : /*!
     412             :   \brief Get feature geometry
     413             : 
     414             :   \return pointer to OGRGeometry or NULL on error
     415             : */
     416        1529 : const OGRGeometry *IVFKFeature::GetGeometry()
     417             : {
     418        1529 :     if (m_nGeometryType != wkbNone && !m_bGeometry)
     419           0 :         LoadGeometry();
     420             : 
     421        1529 :     return m_paGeom.get();
     422             : }
     423             : 
     424             : /*!
     425             :   \brief Load geometry
     426             : 
     427             :   \return true on success or false on failure
     428             : */
     429           0 : bool IVFKFeature::LoadGeometry()
     430             : {
     431           0 :     if (m_bGeometry)
     432           0 :         return true;
     433             : 
     434           0 :     const char *pszName = m_poDataBlock->GetName();
     435             : 
     436           0 :     if (EQUAL(pszName, "SOBR") || EQUAL(pszName, "OBBP") ||
     437           0 :         EQUAL(pszName, "SPOL") || EQUAL(pszName, "OB") ||
     438           0 :         EQUAL(pszName, "OP") || EQUAL(pszName, "OBPEJ"))
     439             :     {
     440             :         /* -> wkbPoint */
     441             : 
     442           0 :         return LoadGeometryPoint();
     443             :     }
     444           0 :     else if (EQUAL(pszName, "SBP") || EQUAL(pszName, "SBPG"))
     445             :     {
     446             :         /* -> wkbLineString */
     447           0 :         return LoadGeometryLineStringSBP();
     448             :     }
     449           0 :     else if (EQUAL(pszName, "HP") || EQUAL(pszName, "DPM") ||
     450           0 :              EQUAL(pszName, "ZVB"))
     451             :     {
     452             :         /* -> wkbLineString */
     453           0 :         return LoadGeometryLineStringHP();
     454             :     }
     455           0 :     else if (EQUAL(pszName, "PAR") || EQUAL(pszName, "BUD"))
     456             :     {
     457             :         /* -> wkbPolygon */
     458           0 :         return LoadGeometryPolygon();
     459             :     }
     460             : 
     461           0 :     return false;
     462             : }
     463             : 
     464             : /*!
     465             :   \brief VFKFeature constructor
     466             : 
     467             :   \param poDataBlock pointer to VFKDataBlock instance
     468             : */
     469         870 : VFKFeature::VFKFeature(IVFKDataBlock *poDataBlock, GIntBig iFID)
     470         870 :     : IVFKFeature(poDataBlock)
     471             : {
     472         870 :     m_nFID = iFID;
     473         870 :     m_propertyList.assign(poDataBlock->GetPropertyCount(), VFKProperty());
     474         870 :     CPLAssert(size_t(poDataBlock->GetPropertyCount()) == m_propertyList.size());
     475         870 : }
     476             : 
     477             : /*!
     478             :   \brief Set feature properties
     479             : 
     480             :   \param pszLine pointer to line containing feature definition
     481             : 
     482             :   \return true on success or false on failure
     483             : */
     484         870 : bool VFKFeature::SetProperties(const char *pszLine)
     485             : {
     486         870 :     const char *poChar = pszLine;  // Used after for.
     487        5310 :     for (; *poChar != '\0' && *poChar != ';'; poChar++)
     488             :         /* skip data block name */
     489             :         ;
     490         870 :     if (*poChar == '\0')
     491           0 :         return false; /* nothing to read */
     492             : 
     493         870 :     poChar++; /* skip ';' after data block name */
     494             : 
     495             :     /* remove extra quotes (otherwise due to buggy format the parsing is
     496             :      * almost impossible) */
     497        1740 :     CPLString osLine;
     498       68760 :     while (*poChar != '\0')
     499             :     {
     500       67890 :         if (*poChar == '"')
     501             :         {
     502             :             /* count quotes */
     503        4380 :             int nQuotes = 1;
     504        5280 :             while (*(++poChar) == '"')
     505         900 :                 nQuotes++;
     506             : 
     507        4380 :             if (nQuotes % 2 != 0)
     508             :             {
     509             :                 /* even number of quotes -> only last quote used */
     510        3480 :                 poChar -= 1;
     511             :             }
     512             :             else
     513             :             {
     514         900 :                 if ((*poChar == ';' || *poChar == '\0') &&
     515         855 :                     *(poChar - nQuotes - 1) == ';')
     516             :                 {
     517             :                     /* empty values (;""; / ;"" / ;""""; / ...)
     518             :                        -> only last two quotes used */
     519         840 :                     poChar -= 2;
     520             :                 }
     521          60 :                 else if (*poChar == '\0')
     522           0 :                     break;
     523             :                 /* odd number of quotes -> none of quotes used */
     524             :             }
     525             :         }
     526       67890 :         osLine += *(poChar++);
     527             :     }
     528         870 :     poChar = osLine;
     529             : 
     530             :     /* read properties into the list */
     531         870 :     const char *poProp = poChar;
     532         870 :     unsigned int iIndex = 0;
     533         870 :     unsigned int nLength = 0;
     534         870 :     unsigned int nQuotes = 0;
     535         870 :     bool inString = false;
     536         870 :     char *pszProp = nullptr;
     537        1740 :     std::vector<CPLString> oPropList;
     538       64440 :     while (*poChar != '\0')
     539             :     {
     540       63615 :         if ((!inString && *poChar == '"') ||               /* begin of string */
     541       17265 :             (inString && *poChar == '"' && nQuotes == 1 && /* end of string */
     542        1320 :              (*(poChar + 1) == ';' || *(poChar + 1) == '\0')))
     543             :         {
     544             : 
     545        3480 :             poChar++; /* skip '"' */
     546        3480 :             inString = !inString;
     547        3480 :             if (inString)
     548             :             {
     549        2160 :                 nQuotes = 1;
     550        2160 :                 poProp = poChar;
     551        2160 :                 if (*poChar == '"' &&
     552         840 :                     (*(poChar + 1) == ';' || *(poChar + 1) == '\0'))
     553             :                 {
     554             :                     /* process empty string */
     555         840 :                     poChar++;
     556         840 :                     inString = false;
     557             :                 }
     558             :                 else
     559             :                 {
     560             :                     /* count number of starting quotes */
     561        1320 :                     while (*poChar == '"')
     562             :                     {
     563           0 :                         nQuotes++;
     564           0 :                         nLength++;
     565           0 :                         poChar++;
     566             :                     }
     567             :                 }
     568             :             }
     569        3480 :             if (*poChar == '\0')
     570             :             {
     571             :                 /* end of line */
     572          45 :                 break;
     573             :             }
     574             :         }
     575       63570 :         if (*poChar == ';' && !inString)
     576             :         {
     577             :             /* end of property */
     578       10050 :             pszProp = (char *)CPLRealloc(pszProp, nLength + 1);
     579       10050 :             if (nLength > 0)
     580        7380 :                 strncpy(pszProp, poProp, nLength);
     581       10050 :             pszProp[nLength] = '\0';
     582             :             /* add new property into the list */
     583       10050 :             oPropList.push_back(pszProp);
     584             :             /* prepare for next property */
     585       10050 :             iIndex++;
     586       10050 :             poProp = ++poChar;
     587       10050 :             nLength = 0;
     588       10050 :             nQuotes = 0;
     589             :         }
     590             :         else
     591             :         {
     592       53520 :             if (*poChar == '"' && nQuotes > 1)
     593           0 :                 nQuotes--;
     594             : 
     595             :             /* add character to property */
     596       53520 :             poChar++;
     597       53520 :             nLength++;
     598             :         }
     599             :     }
     600             :     /* append last property */
     601         870 :     if (inString && nLength > 0)
     602             :     {
     603           0 :         nLength--; /* ignore '"' */
     604             :     }
     605         870 :     pszProp = (char *)CPLRealloc(pszProp, nLength + 1);
     606         870 :     if (nLength > 0)
     607         405 :         strncpy(pszProp, poProp, nLength);
     608         870 :     pszProp[nLength] = '\0';
     609         870 :     oPropList.push_back(pszProp);
     610             : 
     611             :     /* set properties from the list */
     612         870 :     if (oPropList.size() != (size_t)m_poDataBlock->GetPropertyCount())
     613             :     {
     614             :         /* try to read also invalid records */
     615           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     616             :                  "%s: invalid number of properties %d should be %d\n%s",
     617           0 :                  m_poDataBlock->GetName(), (int)oPropList.size(),
     618           0 :                  m_poDataBlock->GetPropertyCount(), pszLine);
     619           0 :         CPLFree(pszProp);
     620           0 :         return false;
     621             :     }
     622         870 :     iIndex = 0;
     623       11790 :     for (std::vector<CPLString>::iterator ip = oPropList.begin();
     624       22710 :          ip != oPropList.end(); ++ip)
     625             :     {
     626       10920 :         SetProperty(iIndex++, (*ip).c_str());
     627             :     }
     628             : 
     629             :     // TODO(martinl): Why was this block disabled?
     630             :     /* set fid
     631             :     if (EQUAL(m_poDataBlock->GetName(), "SBP")) {
     632             :         const VFKProperty *poVfkProperty = GetProperty("PORADOVE_CISLO_BODU");
     633             :         if (poVfkProperty)
     634             :         {
     635             :             GUIntBig id = strtoul(poVfkProperty->GetValueS(), NULL, 0);
     636             :             if (id == 1)
     637             :                 SetFID(0);
     638             :             else
     639             :                 SetFID(-1);
     640             :         }
     641             :     }
     642             :     else {
     643             :         SetFID(0);
     644             :     }
     645             :     */
     646         870 :     CPLFree(pszProp);
     647             : 
     648         870 :     return true;
     649             : }
     650             : 
     651             : /*!
     652             :   \brief Set feature property
     653             : 
     654             :   \param iIndex property index
     655             :   \param pszValue property value
     656             : 
     657             :   \return true on success, false on failure
     658             : */
     659       10920 : bool VFKFeature::SetProperty(int iIndex, const char *pszValue)
     660             : {
     661       21840 :     if (iIndex < 0 || iIndex >= m_poDataBlock->GetPropertyCount() ||
     662       10920 :         size_t(iIndex) >= m_propertyList.size())
     663           0 :         return false;
     664             : 
     665       10920 :     if (strlen(pszValue) < 1)
     666             :     {
     667        3135 :         m_propertyList[iIndex] = VFKProperty();
     668        3135 :         return true;
     669             :     }
     670             : 
     671        7785 :     const OGRFieldType fType = m_poDataBlock->GetProperty(iIndex)->GetType();
     672             : 
     673        7785 :     switch (fType)
     674             :     {
     675        6075 :         case OFTInteger:
     676             :         case OFTInteger64:
     677             :         {
     678        6075 :             errno = 0;
     679        6075 :             int pbOverflow = 0;
     680        6075 :             char *pszLast = nullptr;
     681        6075 :             if (fType == OFTInteger)
     682        4410 :                 m_propertyList[iIndex] = VFKProperty(
     683        4410 :                     static_cast<int>(strtol(pszValue, &pszLast, 10)));
     684             :             else /* OFTInteger64 */
     685        3870 :                 m_propertyList[iIndex] =
     686        7740 :                     VFKProperty(CPLAtoGIntBigEx(pszValue, true, &pbOverflow));
     687             : 
     688        8280 :             if ((fType == OFTInteger &&
     689        2205 :                  (errno == ERANGE || !pszLast || *pszLast)) ||
     690        8280 :                 CPLGetValueType(pszValue) != CPL_VALUE_INTEGER || pbOverflow)
     691           0 :                 CPLError(
     692             :                     CE_Warning, CPLE_AppDefined,
     693             :                     "Value '%s' parsed incompletely to integer " CPL_FRMT_GIB
     694             :                     ".",
     695             :                     pszValue,
     696             :                     (fType == OFTInteger)
     697           0 :                         ? m_propertyList[iIndex].GetValueI()
     698           0 :                         : m_propertyList[iIndex].GetValueI64());
     699        6075 :             break;
     700             :         }
     701         390 :         case OFTReal:
     702         390 :             m_propertyList[iIndex] = VFKProperty(CPLAtof(pszValue));
     703         390 :             break;
     704        1320 :         default:
     705             :             const char *pszEncoding =
     706        1320 :                 m_poDataBlock->GetProperty(iIndex)->GetEncoding();
     707        1320 :             if (pszEncoding)
     708             :             {
     709             :                 char *pszValueEnc =
     710         615 :                     CPLRecode(pszValue, pszEncoding, CPL_ENC_UTF8);
     711         615 :                 m_propertyList[iIndex] = VFKProperty(pszValueEnc);
     712         615 :                 CPLFree(pszValueEnc);
     713             :             }
     714             :             else
     715             :             {
     716         705 :                 m_propertyList[iIndex] = VFKProperty(pszValue);
     717             :             }
     718        1320 :             break;
     719             :     }
     720             : 
     721        7785 :     return true;
     722             : }
     723             : 
     724             : /*!
     725             :   \brief Get property value by index
     726             : 
     727             :   \param iIndex property index
     728             : 
     729             :   \return property value, NULL on error
     730             : */
     731       11355 : const VFKProperty *VFKFeature::GetProperty(int iIndex) const
     732             : {
     733       22710 :     if (iIndex < 0 || iIndex >= m_poDataBlock->GetPropertyCount() ||
     734       11355 :         size_t(iIndex) >= m_propertyList.size())
     735           0 :         return nullptr;
     736             : 
     737       11355 :     const VFKProperty *poProperty = &m_propertyList[iIndex];
     738       11355 :     return poProperty;
     739             : }
     740             : 
     741             : /*!
     742             :   \brief Get property value by name
     743             : 
     744             :   \param pszName property name
     745             : 
     746             :   \return property value, NULL on error
     747             : */
     748         435 : const VFKProperty *VFKFeature::GetProperty(const char *pszName) const
     749             : {
     750         435 :     return GetProperty(m_poDataBlock->GetPropertyIndex(pszName));
     751             : }
     752             : 
     753             : /*!
     754             :   \brief Load geometry (point layers)
     755             : 
     756             :   \todo Really needed?
     757             : 
     758             :   \return true on success, false on failure
     759             : */
     760           0 : bool VFKFeature::LoadGeometryPoint()
     761             : {
     762           0 :     const int i_idxY = m_poDataBlock->GetPropertyIndex("SOURADNICE_Y");
     763           0 :     const int i_idxX = m_poDataBlock->GetPropertyIndex("SOURADNICE_X");
     764           0 :     if (i_idxY < 0 || i_idxX < 0)
     765           0 :         return false;
     766             : 
     767           0 :     auto propertyY = GetProperty(i_idxY);
     768           0 :     auto propertyX = GetProperty(i_idxX);
     769           0 :     if (!propertyY || !propertyX)
     770           0 :         return false;
     771           0 :     const double x = -1.0 * propertyY->GetValueD();
     772           0 :     const double y = -1.0 * propertyX->GetValueD();
     773           0 :     OGRPoint pt(x, y);
     774           0 :     SetGeometry(&pt);
     775             : 
     776           0 :     return true;
     777             : }
     778             : 
     779             : /*!
     780             :   \brief Load geometry (linestring SBP/SBPG layer)
     781             : 
     782             :   \todo Really needed?
     783             : 
     784             :   \return true on success or false on failure
     785             : */
     786           0 : bool VFKFeature::LoadGeometryLineStringSBP()
     787             : {
     788             :     VFKDataBlock *poDataBlockPoints =
     789           0 :         (VFKDataBlock *)m_poDataBlock->GetReader()->GetDataBlock("SOBR");
     790           0 :     if (!poDataBlockPoints)
     791           0 :         return false;
     792             : 
     793           0 :     const int idxId = poDataBlockPoints->GetPropertyIndex("ID");
     794           0 :     const int idxBp_Id = m_poDataBlock->GetPropertyIndex("BP_ID");
     795           0 :     const int idxPCB = m_poDataBlock->GetPropertyIndex("PORADOVE_CISLO_BODU");
     796           0 :     if (idxId < 0 || idxBp_Id < 0 || idxPCB < 0)
     797           0 :         return false;
     798             : 
     799           0 :     VFKFeature *poLine = this;
     800           0 :     OGRLineString OGRLine;
     801             :     while (true)
     802             :     {
     803           0 :         auto property_idxBp_Id = poLine->GetProperty(idxBp_Id);
     804           0 :         if (!property_idxBp_Id)
     805           0 :             break;
     806           0 :         auto property_idxPCB = poLine->GetProperty(idxPCB);
     807           0 :         if (!property_idxPCB)
     808           0 :             break;
     809             : 
     810           0 :         const int id = property_idxBp_Id->GetValueI();
     811           0 :         const int ipcb = property_idxPCB->GetValueI();
     812           0 :         if (OGRLine.getNumPoints() > 0 && ipcb == 1)
     813             :         {
     814           0 :             m_poDataBlock->GetPreviousFeature(); /* push back */
     815           0 :             break;
     816             :         }
     817             : 
     818           0 :         VFKFeature *poPoint = poDataBlockPoints->GetFeature(idxId, id);
     819           0 :         if (!poPoint)
     820             :         {
     821           0 :             continue;
     822             :         }
     823           0 :         const OGRPoint *pt = poPoint->GetGeometry()->toPoint();
     824           0 :         OGRLine.addPoint(pt);
     825             : 
     826           0 :         poLine = (VFKFeature *)m_poDataBlock->GetNextFeature();
     827           0 :         if (!poLine)
     828           0 :             break;
     829           0 :     };
     830             : 
     831           0 :     OGRLine.setCoordinateDimension(2); /* force 2D */
     832           0 :     SetGeometry(&OGRLine);
     833             : 
     834             :     /* reset reading */
     835           0 :     poDataBlockPoints->ResetReading();
     836             : 
     837           0 :     return true;
     838             : }
     839             : 
     840             : /*!
     841             :   \brief Load geometry (linestring HP/DPM layer)
     842             : 
     843             :   \todo Really needed?
     844             : 
     845             :   \return true on success or false on failure
     846             : */
     847           0 : bool VFKFeature::LoadGeometryLineStringHP()
     848             : {
     849             :     VFKDataBlock *poDataBlockLines =
     850           0 :         (VFKDataBlock *)m_poDataBlock->GetReader()->GetDataBlock("SBP");
     851           0 :     if (!poDataBlockLines)
     852           0 :         return false;
     853             : 
     854           0 :     const int idxId = m_poDataBlock->GetPropertyIndex("ID");
     855           0 :     const int idxHp_Id = poDataBlockLines->GetPropertyIndex("HP_ID");
     856           0 :     if (idxId < 0 || idxHp_Id < 0)
     857           0 :         return false;
     858             : 
     859           0 :     auto property = GetProperty(idxId);
     860           0 :     if (!property)
     861           0 :         return false;
     862           0 :     const int id = property->GetValueI();
     863           0 :     VFKFeature *poLine = poDataBlockLines->GetFeature(idxHp_Id, id);
     864           0 :     if (!poLine || !poLine->GetGeometry())
     865           0 :         return false;
     866             : 
     867           0 :     SetGeometry(poLine->GetGeometry());
     868           0 :     poDataBlockLines->ResetReading();
     869             : 
     870           0 :     return true;
     871             : }
     872             : 
     873             : /*!
     874             :   \brief Load geometry (polygon BUD/PAR layers)
     875             : 
     876             :   \todo Implement (really needed?)
     877             : 
     878             :   \return true on success or false on failure
     879             : */
     880           0 : bool VFKFeature::LoadGeometryPolygon()
     881             : {
     882           0 :     return false;
     883             : }
     884             : 
     885           0 : OGRErr VFKFeature::LoadProperties(OGRFeature *poFeature)
     886             : {
     887           0 :     for (int iField = 0; iField < m_poDataBlock->GetPropertyCount(); iField++)
     888             :     {
     889           0 :         auto property = GetProperty(iField);
     890           0 :         if (!property || property->IsNull())
     891           0 :             continue;
     892             : 
     893             :         OGRFieldType fType =
     894           0 :             poFeature->GetDefnRef()->GetFieldDefn(iField)->GetType();
     895           0 :         if (fType == OFTInteger)
     896           0 :             poFeature->SetField(iField, property->GetValueI());
     897           0 :         else if (fType == OFTReal)
     898           0 :             poFeature->SetField(iField, property->GetValueD());
     899             :         else
     900           0 :             poFeature->SetField(iField, property->GetValueS());
     901             :     }
     902             : 
     903           0 :     return OGRERR_NONE;
     904             : }

Generated by: LCOV version 1.14