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

Generated by: LCOV version 1.14