LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vfk - vfkreader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 227 307 73.9 %
Date: 2024-05-04 12:52:34 Functions: 13 19 68.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  VFK Reader
       4             :  * Purpose:  Implements VFKReader class.
       5             :  * Author:   Martin Landa, landa.martin gmail.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009-2018, Martin Landa <landa.martin gmail.com>
       9             :  * Copyright (c) 2012-2018, 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 <sys/stat.h>
      33             : 
      34             : #include "vfkreader.h"
      35             : #include "vfkreaderp.h"
      36             : 
      37             : #include "cpl_conv.h"
      38             : #include "cpl_error.h"
      39             : #include "cpl_string.h"
      40             : 
      41             : #include "ogr_geometry.h"
      42             : 
      43             : static char *GetDataBlockName(const char *);
      44             : 
      45             : /*!
      46             :   \brief IVFKReader destructor
      47             : */
      48          17 : IVFKReader::~IVFKReader()
      49             : {
      50          17 : }
      51             : 
      52             : /*!
      53             :   \brief Create new instance of VFKReader
      54             : 
      55             :   \return pointer to VFKReader instance
      56             : */
      57          17 : IVFKReader *CreateVFKReader(const GDALOpenInfo *poOpenInfo)
      58             : {
      59          17 :     return new VFKReaderSQLite(poOpenInfo);
      60             : }
      61             : 
      62             : /*!
      63             :   \brief VFKReader constructor
      64             : */
      65          17 : VFKReader::VFKReader(const GDALOpenInfo *poOpenInfo)
      66             :     : m_pszEncoding("ISO-8859-2"),  // Encoding, supported are ISO-8859-2,
      67             :                                     // WINDOWS-1250 and UTF-8.
      68          34 :       m_poFD(nullptr), m_pszFilename(CPLStrdup(poOpenInfo->pszFilename)),
      69          34 :       m_poFStat((VSIStatBufL *)CPLCalloc(1, sizeof(VSIStatBufL))),
      70             :       // VFK is provided in two forms - stative and amendment data.
      71             :       m_bAmendment(false),
      72             :       m_bFileField(
      73          34 :           CPLFetchBool(poOpenInfo->papszOpenOptions, "FILE_FIELD", false)),
      74          17 :       m_nDataBlockCount(0), m_papoDataBlock(nullptr)
      75             : {
      76             :     // Open VFK file for reading.
      77          17 :     CPLAssert(nullptr != m_pszFilename);
      78             : 
      79          34 :     if (VSIStatL(m_pszFilename, m_poFStat) != 0 ||
      80          17 :         !VSI_ISREG(m_poFStat->st_mode))
      81             :     {
      82           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "%s is not a regular file.",
      83             :                  m_pszFilename);
      84             :     }
      85             : 
      86          17 :     m_poFD = VSIFOpenL(m_pszFilename, "rb");
      87          17 :     if (m_poFD == nullptr)
      88             :     {
      89           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s.",
      90             :                  m_pszFilename);
      91             :     }
      92          17 : }
      93             : 
      94             : /*!
      95             :   \brief VFKReader destructor
      96             : */
      97          17 : VFKReader::~VFKReader()
      98             : {
      99          17 :     CPLFree(m_pszFilename);
     100             : 
     101          17 :     if (m_poFD)
     102          17 :         VSIFCloseL(m_poFD);
     103          17 :     CPLFree(m_poFStat);
     104             : 
     105             :     /* clear data blocks */
     106         993 :     for (int i = 0; i < m_nDataBlockCount; i++)
     107         976 :         delete m_papoDataBlock[i];
     108          17 :     CPLFree(m_papoDataBlock);
     109          17 : }
     110             : 
     111        1787 : char *GetDataBlockName(const char *pszLine)
     112             : {
     113        1787 :     int n = 0;  // Used after for.
     114        1787 :     const char *pszLineChar = pszLine + 2;
     115             : 
     116        8723 :     for (; *pszLineChar != '\0' && *pszLineChar != ';'; pszLineChar++, n++)
     117             :         ;
     118             : 
     119        1787 :     if (*pszLineChar == '\0')
     120           0 :         return nullptr;
     121             : 
     122        1787 :     char *pszBlockName = (char *)CPLMalloc(n + 1);
     123        1787 :     strncpy(pszBlockName, pszLine + 2, n);
     124        1787 :     pszBlockName[n] = '\0';
     125             : 
     126        1787 :     return pszBlockName;
     127             : }
     128             : 
     129             : /*!
     130             :   \brief Read a line from file
     131             : 
     132             :   \return a NULL terminated string which should be freed with CPLFree().
     133             : */
     134        4828 : char *VFKReader::ReadLine()
     135             : {
     136             :     int nBufLength;
     137             :     const char *pszRawLine =
     138        4828 :         CPLReadLine3L(m_poFD, 100 * 1024, &nBufLength, nullptr);
     139        4828 :     if (pszRawLine == nullptr)
     140           1 :         return nullptr;
     141             : 
     142        4827 :     char *pszLine = (char *)CPLMalloc(nBufLength + 1);
     143        4827 :     memcpy(pszLine, pszRawLine, nBufLength + 1);
     144             : 
     145        4827 :     const int nLineLength = static_cast<int>(strlen(pszRawLine));
     146        4827 :     if (nLineLength != nBufLength)
     147             :     {
     148             :         /* replace nul characters in line by spaces */
     149      746407 :         for (int i = nLineLength; i < nBufLength; i++)
     150             :         {
     151      746078 :             if (pszLine[i] == '\0')
     152      701956 :                 pszLine[i] = ' ';
     153             :         }
     154             :     }
     155             : 
     156        4827 :     return pszLine;
     157             : }
     158             : 
     159             : /*!
     160             :   \brief Load text encoding from header (&HENCODING)
     161             : 
     162             :   Called from VFKReader::ReadDataBlocks()
     163             : */
     164          16 : void VFKReader::ReadEncoding()
     165             : {
     166          16 :     VSIFSeekL(m_poFD, 0, SEEK_SET);
     167          16 :     char *pszLine = nullptr;
     168         318 :     while ((pszLine = ReadLine()) != nullptr)
     169             :     {
     170         318 :         if (strlen(pszLine) < 2 || pszLine[0] != '&')
     171             :         {
     172         107 :             CPLFree(pszLine);
     173         107 :             continue;
     174             :         }
     175         211 :         if (pszLine[1] == 'B' || (pszLine[1] == 'K' && strlen(pszLine) == 2))
     176             :         {
     177             :             /* 'B' record closes the header section */
     178             :             /* 'K' record is end of file */
     179          16 :             CPLFree(pszLine);
     180          16 :             break;
     181             :         }
     182         195 :         if (pszLine[1] != 'H')
     183             :         {
     184             :             /* (not) 'H' header */
     185           0 :             CPLFree(pszLine);
     186           0 :             continue;
     187             :         }
     188             : 
     189         195 :         char *pszKey = pszLine + 2; /* &H */
     190         195 :         char *pszValue = pszKey;
     191        1350 :         while (*pszValue != '\0' && *pszValue != ';')
     192        1155 :             pszValue++;
     193         195 :         if (*pszValue != ';')
     194             :         {
     195             :             /* no value, ignoring */
     196           0 :             CPLFree(pszLine);
     197           0 :             continue;
     198             :         }
     199             : 
     200         195 :         *pszValue = '\0';
     201         195 :         pszValue++; /* skip ; */
     202         195 :         if (*pszValue == '"')
     203             :         { /* trim "" */
     204         105 :             pszValue++;
     205         105 :             size_t nValueLen = strlen(pszValue);
     206         105 :             if (nValueLen > 0)
     207         105 :                 pszValue[nValueLen - 1] = '\0';
     208             :         }
     209             : 
     210             :         /* read encoding to m_pszEncoding */
     211         195 :         if (EQUAL(pszKey, "CODEPAGE"))
     212             :         {
     213          15 :             if (EQUAL(pszValue, CPL_ENC_UTF8))
     214           0 :                 m_pszEncoding = CPL_ENC_UTF8;
     215          15 :             else if (!EQUAL(pszValue, "WE8ISO8859P2"))
     216           0 :                 m_pszEncoding = "WINDOWS-1250";
     217             :         }
     218             : 
     219         195 :         CPLFree(pszLine);
     220             :     }
     221          16 : }
     222             : 
     223             : /*!
     224             :   \brief Load data block definitions (&B)
     225             : 
     226             :   Call VFKReader::OpenFile() before this function.
     227             : 
     228             :   \param bSuppressGeometry True for skipping geometry resolver (force wkbNone
     229             :   type)
     230             : 
     231             :   \return number of data blocks or -1 on error
     232             : */
     233          16 : int VFKReader::ReadDataBlocks(bool bSuppressGeometry)
     234             : {
     235          16 :     CPLAssert(nullptr != m_pszFilename);
     236             : 
     237             :     /* load text encoding in extra pass through header */
     238          16 :     ReadEncoding();
     239             : 
     240          16 :     VSIFSeekL(m_poFD, 0, SEEK_SET);
     241          16 :     bool bInHeader = true;
     242          16 :     char *pszLine = nullptr;
     243        2485 :     while ((pszLine = ReadLine()) != nullptr)
     244             :     {
     245        2484 :         if (strlen(pszLine) < 2 || pszLine[0] != '&')
     246             :         {
     247         487 :             CPLFree(pszLine);
     248         487 :             continue;
     249             :         }
     250             : 
     251        1997 :         if (pszLine[1] == 'B')
     252             :         {
     253         917 :             if (bInHeader)
     254          16 :                 bInHeader = false; /* 'B' record closes the header section */
     255             : 
     256         917 :             char *pszBlockName = GetDataBlockName(pszLine);
     257         917 :             if (pszBlockName == nullptr)
     258             :             {
     259           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     260             :                          "Corrupted data - line\n%s\n", pszLine);
     261           0 :                 CPLFree(pszLine);
     262           0 :                 return -1;
     263             :             }
     264             : 
     265             :             /* skip duplicated data blocks (when reading multiple files into
     266             :              * single DB)  */
     267         917 :             if (!GetDataBlock(pszBlockName))
     268             :             {
     269             :                 IVFKDataBlock *poNewDataBlock =
     270         915 :                     (IVFKDataBlock *)CreateDataBlock(pszBlockName);
     271         915 :                 poNewDataBlock->SetGeometryType(bSuppressGeometry);
     272         915 :                 poNewDataBlock->SetProperties(
     273             :                     pszLine); /* TODO: check consistency on property level */
     274             : 
     275         915 :                 AddDataBlock(poNewDataBlock, pszLine);
     276             :             }
     277         917 :             CPLFree(pszBlockName);
     278             :         }
     279        1080 :         else if (pszLine[1] == 'H')
     280             :         {
     281             :             /* check for amendment file */
     282         195 :             if (EQUAL(pszLine, "&HZMENY;1"))
     283             :             {
     284           0 :                 m_bAmendment = true;
     285             :             }
     286             : 
     287             :             /* header - metadata */
     288         195 :             AddInfo(pszLine);
     289             :         }
     290         885 :         else if (pszLine[1] == 'K' && strlen(pszLine) == 2)
     291             :         {
     292             :             /* end of file */
     293          15 :             CPLFree(pszLine);
     294          15 :             break;
     295             :         }
     296         870 :         else if (bInHeader && pszLine[1] == 'D')
     297             :         {
     298             :             /* process 'D' records in the header section */
     299           0 :             AddInfo(pszLine);
     300             :         }
     301             : 
     302        1982 :         CPLFree(pszLine);
     303             :     }
     304             : 
     305          16 :     return m_nDataBlockCount;
     306             : }
     307             : 
     308             : /*!
     309             :   \brief Load data records (&D)
     310             : 
     311             :   Call VFKReader::OpenFile() before this function.
     312             : 
     313             :   \param poDataBlock limit to selected data block or NULL for all
     314             : 
     315             :   \return number of data records or -1 on error
     316             : */
     317          15 : int VFKReader::ReadDataRecords(IVFKDataBlock *poDataBlock)
     318             : {
     319          15 :     const char *pszName = nullptr;
     320          15 :     IVFKDataBlock *poDataBlockCurrent = nullptr;
     321             : 
     322          15 :     if (poDataBlock)
     323             :     { /* read only given data block */
     324           0 :         poDataBlockCurrent = poDataBlock;
     325           0 :         if (poDataBlockCurrent->GetFeatureCount(FALSE) < 0)
     326           0 :             poDataBlockCurrent->SetFeatureCount(0);
     327           0 :         pszName = poDataBlockCurrent->GetName();
     328             :     }
     329             :     else
     330             :     { /* read all data blocks */
     331         930 :         for (int iDataBlock = 0; iDataBlock < GetDataBlockCount(); iDataBlock++)
     332             :         {
     333         915 :             poDataBlockCurrent = GetDataBlock(iDataBlock);
     334         915 :             if (poDataBlockCurrent->GetFeatureCount(FALSE) < 0)
     335         915 :                 poDataBlockCurrent->SetFeatureCount(0);
     336             :         }
     337          15 :         poDataBlockCurrent = nullptr;
     338             :     }
     339             : 
     340          15 :     VSIFSeekL(m_poFD, 0, SEEK_SET);
     341             : 
     342          15 :     int iLine = 0;
     343          15 :     int nSkipped = 0;
     344          15 :     int nDupl = 0;
     345          15 :     int nRecords = 0;
     346          15 :     bool bInHeader = true;
     347          30 :     CPLString osBlockNameLast;
     348          15 :     char *pszLine = nullptr;
     349             : 
     350             :     /* currency sign in current encoding */
     351          15 :     const char *pszCurSign = "\244";
     352          15 :     if (EQUAL(m_pszEncoding, CPL_ENC_UTF8))
     353           0 :         pszCurSign = "\302\244";
     354          15 :     size_t nCurSignLen = strlen(pszCurSign);
     355             : 
     356        1995 :     while ((pszLine = ReadLine()) != nullptr)
     357             :     {
     358        1995 :         iLine++;
     359        1995 :         size_t nLength = strlen(pszLine);
     360        1995 :         if (nLength < 2)
     361             :         {
     362           0 :             CPLFree(pszLine);
     363           0 :             continue;
     364             :         }
     365             : 
     366        1995 :         if (bInHeader && pszLine[1] == 'B')
     367          15 :             bInHeader = false; /* 'B' record closes the header section */
     368             : 
     369        1995 :         if (pszLine[1] == 'D')
     370             :         {
     371         870 :             if (bInHeader)
     372             :             {
     373             :                 /* skip 'D' records from the header section, already
     374             :                  * processed as metadata */
     375           0 :                 CPLFree(pszLine);
     376           0 :                 continue;
     377             :             }
     378             : 
     379         870 :             char *pszBlockName = GetDataBlockName(pszLine);
     380             : 
     381         870 :             if (pszBlockName && (!pszName || EQUAL(pszBlockName, pszName)))
     382             :             {
     383             :                 /* merge lines if needed
     384             : 
     385             :                    See http://en.wikipedia.org/wiki/ISO/IEC_8859
     386             :                    - \244 - general currency sign
     387             :                 */
     388         870 :                 if (EQUAL(pszLine + nLength - nCurSignLen, pszCurSign))
     389             :                 {
     390             :                     /* trim the currency sign and trailing spaces from line */
     391          30 :                     nLength -= nCurSignLen;
     392          30 :                     while (nLength > 0 && pszLine[nLength - 1] == ' ')
     393           0 :                         nLength--;
     394          30 :                     pszLine[nLength] = '\0';
     395             : 
     396          30 :                     CPLString osMultiLine(pszLine);
     397          30 :                     CPLFree(pszLine);
     398             : 
     399          30 :                     while ((pszLine = ReadLine()) != nullptr &&
     400          60 :                            (nLength = strlen(pszLine)) >= nCurSignLen &&
     401          30 :                            EQUAL(pszLine + nLength - nCurSignLen, pszCurSign))
     402             :                     {
     403             :                         /* trim leading spaces from continued line */
     404           0 :                         char *pszLineTrim = pszLine;
     405           0 :                         while (*pszLineTrim == ' ')
     406           0 :                             pszLineTrim++;
     407             :                         /* trim the currency sign and trailing spaces from line
     408             :                          */
     409           0 :                         nLength = strlen(pszLineTrim) - nCurSignLen;
     410           0 :                         while (nLength > 0 && pszLineTrim[nLength - 1] == ' ')
     411           0 :                             nLength--;
     412           0 :                         pszLineTrim[nLength] = '\0';
     413             :                         /* append a space and the trimmed line */
     414           0 :                         osMultiLine += " ";
     415           0 :                         osMultiLine += pszLineTrim;
     416             : 
     417           0 :                         CPLFree(pszLine);
     418           0 :                         if (osMultiLine.size() > 100U * 1024U * 1024U)
     419             :                         {
     420           0 :                             CPLFree(pszBlockName);
     421           0 :                             return -1;
     422             :                         }
     423             :                     }
     424          30 :                     if (pszLine)
     425             :                     {
     426             :                         /* trim leading spaces from continued line */
     427          30 :                         char *pszLineTrim = pszLine;
     428          30 :                         while (*pszLineTrim == ' ')
     429           0 :                             pszLineTrim++;
     430             :                         /* append a space and the trimmed line */
     431          30 :                         osMultiLine += " ";
     432          30 :                         osMultiLine += pszLineTrim;
     433             :                     }
     434          30 :                     CPLFree(pszLine);
     435             : 
     436          30 :                     nLength = osMultiLine.size();
     437          30 :                     if (nLength > 100U * 1024U * 1024U)
     438             :                     {
     439           0 :                         CPLFree(pszBlockName);
     440           0 :                         return -1;
     441             :                     }
     442          30 :                     pszLine = (char *)CPLMalloc(nLength + 1);
     443          30 :                     strncpy(pszLine, osMultiLine.c_str(), nLength);
     444          30 :                     pszLine[nLength] = '\0';
     445             :                 }
     446             : 
     447         870 :                 if (!poDataBlock)
     448             :                 { /* read all data blocks */
     449        1725 :                     if (osBlockNameLast.empty() ||
     450         855 :                         !EQUAL(pszBlockName, osBlockNameLast.c_str()))
     451             :                     {
     452          75 :                         poDataBlockCurrent = GetDataBlock(pszBlockName);
     453          75 :                         osBlockNameLast = CPLString(pszBlockName);
     454             :                     }
     455             :                 }
     456         870 :                 if (!poDataBlockCurrent)
     457             :                 {
     458           0 :                     CPLFree(pszBlockName);
     459           0 :                     CPLFree(pszLine);
     460           0 :                     continue;  // assert ?
     461             :                 }
     462             : 
     463             :                 VFKFeature *poNewFeature =
     464             :                     new VFKFeature(poDataBlockCurrent,
     465         870 :                                    poDataBlockCurrent->GetFeatureCount() + 1);
     466         870 :                 if (poNewFeature->SetProperties(pszLine))
     467             :                 {
     468         870 :                     if (AddFeature(poDataBlockCurrent, poNewFeature) !=
     469             :                         OGRERR_NONE)
     470             :                     {
     471           0 :                         CPLDebug("OGR-VFK",
     472             :                                  "%s: duplicated VFK data record skipped "
     473             :                                  "(line %d).\n%s\n",
     474             :                                  pszBlockName, iLine, pszLine);
     475           0 :                         poDataBlockCurrent->SetIncRecordCount(RecordDuplicated);
     476             :                     }
     477             :                     else
     478             :                     {
     479         870 :                         nRecords++;
     480         870 :                         poDataBlockCurrent->SetIncRecordCount(RecordValid);
     481             :                     }
     482         870 :                     delete poNewFeature;
     483             :                 }
     484             :                 else
     485             :                 {
     486           0 :                     CPLDebug("OGR-VFK",
     487             :                              "Invalid VFK data record skipped (line %d).\n%s\n",
     488             :                              iLine, pszLine);
     489           0 :                     poDataBlockCurrent->SetIncRecordCount(RecordSkipped);
     490           0 :                     delete poNewFeature;
     491             :                 }
     492             :             }
     493         870 :             CPLFree(pszBlockName);
     494             :         }
     495        1125 :         else if (pszLine[1] == 'K' && strlen(pszLine) == 2)
     496             :         {
     497             :             /* end of file */
     498          15 :             CPLFree(pszLine);
     499          15 :             break;
     500             :         }
     501             : 
     502        1980 :         CPLFree(pszLine);
     503             :     }
     504             : 
     505         930 :     for (int iDataBlock = 0; iDataBlock < GetDataBlockCount(); iDataBlock++)
     506             :     {
     507         915 :         poDataBlockCurrent = GetDataBlock(iDataBlock);
     508             : 
     509         915 :         if (poDataBlock && poDataBlock != poDataBlockCurrent)
     510           0 :             continue;
     511             : 
     512         915 :         nSkipped = poDataBlockCurrent->GetRecordCount(RecordSkipped);
     513         915 :         nDupl = poDataBlockCurrent->GetRecordCount(RecordDuplicated);
     514         915 :         if (nSkipped > 0)
     515           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     516             :                      "%s: %d invalid VFK data records skipped",
     517             :                      poDataBlockCurrent->GetName(), nSkipped);
     518         915 :         if (nDupl > 0)
     519           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     520             :                      "%s: %d duplicated VFK data records skipped",
     521             :                      poDataBlockCurrent->GetName(), nDupl);
     522             : 
     523         915 :         CPLDebug("OGR-VFK", "VFKReader::ReadDataRecords(): name=%s n=%d",
     524             :                  poDataBlockCurrent->GetName(),
     525             :                  poDataBlockCurrent->GetRecordCount(RecordValid));
     526             :     }
     527             : 
     528          15 :     return nRecords;
     529             : }
     530             : 
     531           0 : IVFKDataBlock *VFKReader::CreateDataBlock(const char *pszBlockName)
     532             : {
     533           0 :     return (IVFKDataBlock *)new VFKDataBlock(pszBlockName, (IVFKReader *)this);
     534             : }
     535             : 
     536             : /*!
     537             :   \brief Add new data block
     538             : 
     539             :   \param poNewDataBlock pointer to VFKDataBlock instance
     540             :   \param pszDefn unused (see VFKReaderSQLite::AddDataBlock)
     541             : */
     542         976 : void VFKReader::AddDataBlock(IVFKDataBlock *poNewDataBlock,
     543             :                              CPL_UNUSED const char *pszDefn)
     544             : {
     545         976 :     m_nDataBlockCount++;
     546             : 
     547        1952 :     m_papoDataBlock = (IVFKDataBlock **)CPLRealloc(
     548         976 :         m_papoDataBlock, sizeof(IVFKDataBlock *) * m_nDataBlockCount);
     549         976 :     m_papoDataBlock[m_nDataBlockCount - 1] = poNewDataBlock;
     550         976 : }
     551             : 
     552             : /*!
     553             :   \brief Add feature
     554             : 
     555             :   \param poDataBlock pointer to VFKDataBlock instance
     556             :   \param poFeature pointer to VFKFeature instance
     557             : */
     558           0 : OGRErr VFKReader::AddFeature(IVFKDataBlock *poDataBlock, VFKFeature *poFeature)
     559             : {
     560           0 :     poDataBlock->AddFeature(poFeature);
     561           0 :     return OGRERR_NONE;
     562             : }
     563             : 
     564             : /*!
     565             :   \brief Get data block
     566             : 
     567             :   \param i index (starting with 0)
     568             : 
     569             :   \return pointer to VFKDataBlock instance or NULL on failure
     570             : */
     571       72009 : IVFKDataBlock *VFKReader::GetDataBlock(int i) const
     572             : {
     573       72009 :     if (i < 0 || i >= m_nDataBlockCount)
     574           0 :         return nullptr;
     575             : 
     576       72009 :     return m_papoDataBlock[i];
     577             : }
     578             : 
     579             : /*!
     580             :   \brief Get data block
     581             : 
     582             :   \param pszName data block name
     583             : 
     584             :   \return pointer to VFKDataBlock instance or NULL on failure
     585             : */
     586        2073 : IVFKDataBlock *VFKReader::GetDataBlock(const char *pszName) const
     587             : {
     588       66154 :     for (int i = 0; i < m_nDataBlockCount; i++)
     589             :     {
     590       65239 :         if (EQUAL(GetDataBlock(i)->GetName(), pszName))
     591        1158 :             return GetDataBlock(i);
     592             :     }
     593             : 
     594         915 :     return nullptr;
     595             : }
     596             : 
     597             : /*!
     598             :   \brief Load geometry (loop datablocks)
     599             : 
     600             :   \return number of invalid features
     601             : */
     602           0 : int VFKReader::LoadGeometry()
     603             : {
     604           0 :     long int nfeatures = 0;
     605           0 :     for (int i = 0; i < m_nDataBlockCount; i++)
     606             :     {
     607           0 :         nfeatures += m_papoDataBlock[i]->LoadGeometry();
     608             :     }
     609             : 
     610           0 :     CPLDebug("OGR_VFK", "VFKReader::LoadGeometry(): invalid=%ld", nfeatures);
     611             : 
     612           0 :     return static_cast<int>(nfeatures);
     613             : }
     614             : 
     615             : /*!
     616             :   \brief Add info
     617             : 
     618             :   \param pszLine pointer to line
     619             : */
     620         195 : void VFKReader::AddInfo(const char *pszLine)
     621             : {
     622         195 :     const int nOffset = pszLine[1] == 'H' ? 2 : 1;  // &DKATUZE
     623             : 
     624         195 :     const char *poKey = pszLine + nOffset; /* &H */
     625         195 :     const char *poChar = poKey;
     626         195 :     int iKeyLength = 0;
     627        1350 :     while (*poChar != '\0' && *poChar != ';')
     628             :     {
     629        1155 :         iKeyLength++;
     630        1155 :         poChar++;
     631             :     }
     632         195 :     if (*poChar == '\0')
     633           0 :         return;
     634             : 
     635         195 :     char *pszKey = (char *)CPLMalloc(iKeyLength + 1);
     636         195 :     strncpy(pszKey, poKey, iKeyLength);
     637         195 :     pszKey[iKeyLength] = '\0';
     638             : 
     639         195 :     poChar++; /* skip ; */
     640             : 
     641         195 :     int iValueLength = 0;
     642         195 :     int nSkip = 3; /* &H + ; */
     643       17460 :     while (*poChar != '\0')
     644             :     {
     645       17265 :         if (*poChar == '"' && iValueLength == 0)
     646             :         {
     647         105 :             nSkip++;
     648             :         }
     649             :         else
     650             :         {
     651       17160 :             iValueLength++;
     652             :         }
     653       17265 :         poChar++;
     654             :     }
     655         195 :     if (nSkip > 3 && iValueLength > 0)
     656         105 :         iValueLength--;
     657             : 
     658         195 :     char *pszValue = (char *)CPLMalloc(iValueLength + 1);
     659       17250 :     for (int i = 0; i < iValueLength; i++)
     660             :     {
     661       17055 :         pszValue[i] = pszLine[iKeyLength + nSkip + i];
     662       17055 :         if (pszValue[i] == '"')
     663             :         {
     664         270 :             pszValue[i] = '\''; /* " -> ' */
     665             :         }
     666             :     }
     667             : 
     668         195 :     pszValue[iValueLength] = '\0';
     669             : 
     670             :     /* recode values */
     671         195 :     char *pszValueEnc = CPLRecode(pszValue, m_pszEncoding, CPL_ENC_UTF8);
     672             : 
     673         195 :     if (poInfo.find(pszKey) == poInfo.end())
     674             :     {
     675         195 :         poInfo[pszKey] = pszValueEnc;
     676             :     }
     677             :     else
     678             :     {
     679             :         /* max. number of duplicated keys can be 101 */
     680           0 :         const size_t nLen = strlen(pszKey) + 5;
     681           0 :         char *pszKeyUniq = (char *)CPLMalloc(nLen);
     682             : 
     683           0 :         int nCount = 1; /* assuming at least one match */
     684           0 :         for (std::map<CPLString, CPLString>::iterator i = poInfo.begin();
     685           0 :              i != poInfo.end(); ++i)
     686             :         {
     687           0 :             size_t iFound = i->first.find("_");
     688           0 :             if (iFound != std::string::npos &&
     689           0 :                 EQUALN(pszKey, i->first.c_str(), iFound))
     690           0 :                 nCount += 1;
     691             :         }
     692             : 
     693           0 :         snprintf(pszKeyUniq, nLen, "%s_%d", pszKey, nCount);
     694           0 :         poInfo[pszKeyUniq] = pszValueEnc;
     695           0 :         CPLFree(pszKeyUniq);
     696             :     }
     697             : 
     698         195 :     CPLFree(pszKey);
     699         195 :     CPLFree(pszValue);
     700         195 :     CPLFree(pszValueEnc);
     701             : }
     702             : 
     703             : /*!
     704             :   \brief Get info
     705             : 
     706             :   \param key key string
     707             : 
     708             :   \return pointer to value string or NULL if key not found
     709             : */
     710           0 : const char *VFKReader::GetInfo(const char *key)
     711             : {
     712           0 :     if (poInfo.find(key) == poInfo.end())
     713           0 :         return nullptr;
     714             : 
     715           0 :     return poInfo[key].c_str();
     716             : }

Generated by: LCOV version 1.14