LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/vfk - vfkreader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 172 120 69.8 %
Date: 2013-03-30 Functions: 21 12 57.1 %

       1                 : /******************************************************************************
       2                 :  * $Id: vfkreader.cpp 25721 2013-03-09 16:21:46Z martinl $
       3                 :  *
       4                 :  * Project:  VFK Reader
       5                 :  * Purpose:  Implements VFKReader class.
       6                 :  * Author:   Martin Landa, landa.martin gmail.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2009-2010, 2012-2013, Martin Landa <landa.martin gmail.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                 : #include "cpl_string.h"
      38                 : 
      39                 : #define SUPPORT_GEOMETRY
      40                 : 
      41                 : #ifdef SUPPORT_GEOMETRY
      42                 : #  include "ogr_geometry.h"
      43                 : #endif
      44                 : 
      45                 : static char *GetDataBlockName(const char *);
      46                 : 
      47                 : /*!
      48                 :   \brief IVFKReader desctructor
      49                 : */
      50               2 : IVFKReader::~IVFKReader()
      51                 : {
      52               2 : }
      53                 : 
      54                 : /*!
      55                 :   \brief Create new instance of VFKReader
      56                 : 
      57                 :   \return pointer to VFKReader instance
      58                 : */
      59               2 : IVFKReader *CreateVFKReader(const char *pszFilename)
      60                 : {
      61               2 :     return new VFKReaderSQLite(pszFilename);
      62                 : }
      63                 : 
      64                 : /*!
      65                 :   \brief VFKReader constructor
      66                 : */
      67               2 : VFKReader::VFKReader(const char *pszFilename)
      68                 : {
      69               2 :     m_nDataBlockCount = 0;
      70               2 :     m_papoDataBlock   = NULL;
      71               2 :     m_bLatin2         = TRUE; /* encoding ISO-8859-2 or WINDOWS-1250 */
      72                 : 
      73                 :     /* open VFK file for reading */
      74               2 :     CPLAssert(NULL != pszFilename);
      75               2 :     m_pszFilename = CPLStrdup(pszFilename);
      76               2 :     m_poFD = VSIFOpen(m_pszFilename, "rb");
      77               2 :     if (m_poFD == NULL) {
      78                 :         CPLError(CE_Failure, CPLE_OpenFailed, 
      79               0 :                  "Failed to open file %s.", m_pszFilename);
      80                 :     }
      81               2 : }
      82                 : 
      83                 : /*!
      84                 :   \brief VFKReader destructor
      85                 : */
      86               2 : VFKReader::~VFKReader()
      87                 : {
      88               2 :     CPLFree(m_pszFilename);
      89                 : 
      90               2 :     if (m_poFD)
      91               2 :         VSIFClose(m_poFD);
      92                 :     
      93                 :     /* clear data blocks */
      94             124 :     for (int i = 0; i < m_nDataBlockCount; i++)
      95             122 :         delete m_papoDataBlock[i];
      96               2 :     CPLFree(m_papoDataBlock);
      97               2 : }
      98                 : 
      99             273 : char *GetDataBlockName(const char *pszLine)
     100                 : {
     101                 :     int         n;
     102                 :     const char *pszLineChar;
     103                 :     char       *pszBlockName;
     104                 : 
     105             273 :     for (pszLineChar = pszLine + 2, n = 0; *pszLineChar != '\0' && *pszLineChar != ';'; pszLineChar++, n++)
     106                 :         ;
     107                 : 
     108             273 :     if (*pszLineChar == '\0')
     109               0 :         return NULL;
     110                 : 
     111             273 :     pszBlockName = (char *) CPLMalloc(n + 1);
     112             273 :     strncpy(pszBlockName, pszLine + 2, n);
     113             273 :     pszBlockName[n] = '\0';
     114                 : 
     115             273 :     return pszBlockName;
     116                 : }
     117                 : 
     118                 : /*!
     119                 :   \brief Read a line from file
     120                 :  
     121                 :   \param bRecode do recoding
     122                 : 
     123                 :   \return a NULL terminated string which should be freed with CPLFree().
     124                 : */
     125             640 : char *VFKReader::ReadLine(bool bRecode)
     126                 : {
     127                 :     const char *pszRawLine;
     128                 :     char *pszLine;
     129                 :     
     130             640 :     pszRawLine = CPLReadLine(m_poFD);
     131             640 :     if (pszRawLine == NULL)
     132               0 :         return NULL;
     133                 :     
     134             640 :     if (bRecode)
     135                 :         pszLine = CPLRecode(pszRawLine,
     136                 :                             m_bLatin2 ? "ISO-8859-2" : "WINDOWS-1250",
     137               0 :                             CPL_ENC_UTF8);
     138                 :     else {
     139             640 :         pszLine = (char *) CPLMalloc(strlen(pszRawLine) + 1);
     140             640 :         strcpy(pszLine, pszRawLine);
     141                 :     }
     142                 :     
     143             640 :     return pszLine;
     144                 : }
     145                 : 
     146                 : /*!
     147                 :   \brief Load data block definitions (&B)
     148                 : 
     149                 :   Call VFKReader::OpenFile() before this function.
     150                 : 
     151                 :   \return number of data blocks or -1 on error
     152                 : */
     153               1 : int VFKReader::ReadDataBlocks()
     154                 : {
     155                 :     char       *pszLine, *pszBlockName;
     156                 : 
     157                 :     IVFKDataBlock *poNewDataBlock;
     158                 :     
     159               1 :     CPLAssert(NULL != m_pszFilename);
     160                 : 
     161               1 :     VSIFSeek(m_poFD, 0, SEEK_SET);
     162             129 :     while ((pszLine = ReadLine()) != NULL) {
     163             128 :         if (strlen(pszLine) < 2 || pszLine[0] != '&')
     164                 :         {
     165               0 :             CPLFree(pszLine);
     166               0 :             continue;
     167                 :         }
     168             128 :         if (pszLine[1] == 'B') {
     169              61 :             pszBlockName = GetDataBlockName(pszLine);
     170              61 :             if (pszBlockName == NULL) { 
     171                 :                 CPLError(CE_Failure, CPLE_NotSupported, 
     172               0 :                          "Corrupted data - line\n%s\n", pszLine);
     173               0 :                 CPLFree(pszLine);
     174               0 :                 return -1;
     175                 :             }
     176              61 :             poNewDataBlock = (IVFKDataBlock *) CreateDataBlock(pszBlockName);
     177              61 :             CPLFree(pszBlockName);
     178              61 :             poNewDataBlock->SetGeometryType();
     179              61 :             poNewDataBlock->SetProperties(pszLine);
     180              61 :             AddDataBlock(poNewDataBlock, pszLine);
     181                 :         }
     182              67 :         else if (pszLine[1] == 'H') {
     183                 :             /* header - metadata */
     184              13 :             AddInfo(pszLine);
     185                 :         }
     186              54 :         else if (pszLine[1] == 'K' && strlen(pszLine) == 2) {
     187                 :             /* end of file */
     188               1 :             CPLFree(pszLine);
     189               1 :             break;
     190                 :         }
     191             127 :         CPLFree(pszLine);
     192                 :     }
     193                 :     
     194               1 :     return m_nDataBlockCount;
     195                 : }
     196                 : 
     197                 : 
     198                 : /*!
     199                 :   \brief Load data records (&D)
     200                 : 
     201                 :   Call VFKReader::OpenFile() before this function.
     202                 :   
     203                 :   \return number of data records or -1 on error
     204                 : */
     205               4 : int VFKReader::ReadDataRecords(IVFKDataBlock *poDataBlock)
     206                 : {
     207                 :     const char *pszName;
     208                 :     char       *pszBlockName, *pszLine;
     209                 :     long        iFID;
     210                 :     int         nLength, iLine, nSkipped, nDupl, nRecords;
     211                 :     
     212               4 :     CPLString pszMultiLine;
     213                 : 
     214                 :     VFKFeature *poNewFeature;
     215                 :     
     216               4 :     poDataBlock->SetFeatureCount(0);
     217               4 :     pszName = poDataBlock->GetName();
     218                 : 
     219               4 :     VSIFSeek(m_poFD, 0, SEEK_SET);
     220               4 :     iFID = 1L;
     221               4 :     iLine = nSkipped = nDupl = nRecords = 0;
     222             516 :     while ((pszLine = ReadLine()) != NULL) {
     223             512 :         iLine++;
     224             512 :         nLength = strlen(pszLine);
     225             512 :         if (nLength < 2)
     226               0 :             continue;
     227                 :         
     228             512 :         if (pszLine[1] == 'D') {
     229             212 :             pszBlockName = GetDataBlockName(pszLine);
     230             212 :             if (pszBlockName && EQUAL(pszBlockName, pszName)) {
     231                 :                 /* merge lines if needed */
     232              53 :                 if (pszLine[nLength - 2] == '\302' &&
     233               0 :                     pszLine[nLength - 1] == '\244') {
     234                 :                     
     235                 :                     /* remove 0302 0244 (currency sign) from string */
     236               0 :                     pszLine[nLength - 2] = '\0';
     237                 :                     
     238               0 :                     pszMultiLine.clear();
     239               0 :                     pszMultiLine = pszLine;
     240               0 :                     CPLFree(pszLine);
     241                 :                     
     242               0 :                     while ((pszLine = ReadLine()) != NULL &&
     243               0 :                            pszLine[strlen(pszLine) - 2] == '\302' &&
     244               0 :                            pszLine[strlen(pszLine) - 1] == '\244') {
     245                 :                         /* append line */
     246               0 :                         pszMultiLine += pszLine;
     247                 :                         /* remove 0302 0244 (currency sign) from string */
     248               0 :                         pszMultiLine[strlen(pszLine) - 2] = '\0';
     249                 : 
     250               0 :                         CPLFree(pszLine);
     251                 :                     } 
     252               0 :                     pszMultiLine += pszLine;
     253               0 :                     CPLFree(pszLine);
     254                 :                     
     255               0 :                     nLength = pszMultiLine.size();
     256               0 :                     pszLine = (char *) CPLMalloc(nLength + 1);
     257               0 :                     strncpy(pszLine, pszMultiLine.c_str(), nLength);
     258               0 :                     pszLine[nLength] = '\0';
     259                 :                 }
     260                 :                 
     261              53 :                 poNewFeature = new VFKFeature(poDataBlock, iFID++);
     262             106 :                 if (poNewFeature->SetProperties(pszLine)) {
     263              53 :                     if (AddFeature(poDataBlock, poNewFeature) != OGRERR_NONE) {
     264                 :                         CPLDebug("OGR-VFK", 
     265                 :                                  "%s: duplicated VFK data recored skipped (line %d).\n%s\n",
     266               0 :                                  pszBlockName, iLine, pszLine);
     267               0 :                         nDupl++;
     268               0 :                         iFID--;
     269                 :                     }
     270                 :                     else {
     271              53 :                         nRecords++;
     272                 :                     }
     273              53 :                     delete poNewFeature;
     274                 :     }
     275                 :                 else {
     276                 :                     CPLDebug("OGR-VFK", 
     277               0 :                              "Invalid VFK data record skipped (line %d).\n%s\n", iLine, pszLine);
     278               0 :         nSkipped++;
     279                 :     }
     280                 :             }
     281             212 :             CPLFree(pszBlockName);
     282                 :         }
     283             300 :         else if (pszLine[1] == 'K' && strlen(pszLine) == 2) {
     284                 :             /* end of file */
     285               4 :             CPLFree(pszLine);
     286               4 :             break;
     287                 :         }
     288             508 :         CPLFree(pszLine);
     289                 :     }
     290                 :     
     291               4 :     if (nSkipped > 0)
     292                 :   CPLError(CE_Warning, CPLE_AppDefined, 
     293                 :      "%s: %d invalid VFK data records skipped",
     294               0 :                  poDataBlock->GetName(), nSkipped);
     295               4 :     if (nDupl > 0)
     296                 :   CPLError(CE_Warning, CPLE_AppDefined, 
     297                 :      "%s: %d duplicated VFK data records skipped",
     298               0 :                  poDataBlock->GetName(), nDupl);
     299                 : 
     300                 :     CPLDebug("OGR_VFK", "VFKReader::ReadDataRecords(): name=%s n=%d",
     301               4 :              poDataBlock->GetName(), nRecords);
     302                 : 
     303               4 :     return nRecords;
     304                 : }
     305                 : 
     306               0 : IVFKDataBlock *VFKReader::CreateDataBlock(const char *pszBlockName)
     307                 : {
     308               0 :   return (IVFKDataBlock *) new VFKDataBlock(pszBlockName, (IVFKReader *) this);
     309                 : }
     310                 : 
     311                 : /*!
     312                 :   \brief Add new data block
     313                 : 
     314                 :   \param poNewDataBlock pointer to VFKDataBlock instance
     315                 :   \param pszDefn unused (FIXME ?)
     316                 : */
     317             122 : void VFKReader::AddDataBlock(IVFKDataBlock *poNewDataBlock, const char *pszDefn)
     318                 : {
     319             122 :     m_nDataBlockCount++;
     320                 :     
     321                 :     m_papoDataBlock = (IVFKDataBlock **)
     322             122 :         CPLRealloc(m_papoDataBlock, sizeof (IVFKDataBlock *) * m_nDataBlockCount);
     323             122 :     m_papoDataBlock[m_nDataBlockCount-1] = poNewDataBlock;
     324             122 : }
     325                 : 
     326                 : /*!
     327                 :   \brief Add feature
     328                 : 
     329                 :   \param poDataBlock pointer to VFKDataBlock instance
     330                 :   \param poFeature pointer to VFKFeature instance
     331                 : */
     332               0 : OGRErr VFKReader::AddFeature(IVFKDataBlock *poDataBlock, VFKFeature *poFeature)
     333                 : {
     334               0 :     poDataBlock->AddFeature(poFeature);
     335               0 :     return OGRERR_NONE;
     336                 : }
     337                 : 
     338                 : /*!
     339                 :   \brief Get data block
     340                 : 
     341                 :   \param i index (starting with 0)
     342                 : 
     343                 :   \return pointer to VFKDataBlock instance or NULL on failure
     344                 : */
     345            4308 : IVFKDataBlock *VFKReader::GetDataBlock(int i) const
     346                 : {
     347            4308 :     if (i < 0 || i >= m_nDataBlockCount)
     348               0 :         return NULL;
     349                 :     
     350            4308 :     return m_papoDataBlock[i];
     351                 : }
     352                 : 
     353                 : /*!
     354                 :   \brief Get data block
     355                 : 
     356                 :   \param pszName data block name
     357                 : 
     358                 :   \return pointer to VFKDataBlock instance or NULL on failure
     359                 : */
     360             128 : IVFKDataBlock *VFKReader::GetDataBlock(const char *pszName) const
     361                 : {
     362            4058 :     for (int i = 0; i < m_nDataBlockCount; i++) {
     363            4058 :         if (EQUAL(GetDataBlock(i)->GetName(), pszName))
     364             128 :             return GetDataBlock(i);
     365                 :     }
     366                 : 
     367               0 :     return NULL;
     368                 : }
     369                 : 
     370                 : /*!
     371                 :   \brief Load geometry (loop datablocks)
     372                 : 
     373                 :   \return number of invalid features
     374                 : */
     375               0 : int VFKReader::LoadGeometry()
     376                 : {
     377                 :     long int nfeatures;
     378                 : 
     379               0 :     nfeatures = 0;
     380               0 :     for (int i = 0; i < m_nDataBlockCount; i++) {
     381               0 :         nfeatures += m_papoDataBlock[i]->LoadGeometry();
     382                 :     }
     383                 :     
     384               0 :     CPLDebug("OGR_VFK", "VFKReader::LoadGeometry(): invalid=%ld", nfeatures);
     385                 :     
     386               0 :     return nfeatures;
     387                 : }
     388                 : 
     389                 : /*!
     390                 :   \brief Add info
     391                 : 
     392                 :   \param pszLine pointer to line
     393                 : */
     394              13 : void VFKReader::AddInfo(const char *pszLine)
     395                 : {
     396                 :     int         iKeyLength, iValueLength;
     397                 :     char       *pszKey, *pszValue;
     398                 :     const char *poChar, *poKey, *poValue;
     399              13 :     CPLString   key, value;
     400                 :     
     401              13 :     poChar = poKey = pszLine + 2; /* &H */
     402              13 :     iKeyLength = 0;
     403             103 :     while (*poChar != '\0' && *poChar != ';') {
     404              77 :         iKeyLength++;
     405              77 :         poChar ++;
     406                 :     }
     407              13 :     if (*poChar == '\0')
     408                 :         return;
     409                 : 
     410              13 :     pszKey = (char *) CPLMalloc(iKeyLength + 1);
     411              13 :     strncpy(pszKey, poKey, iKeyLength);
     412              13 :     pszKey[iKeyLength] = '\0';
     413                 : 
     414              13 :     poValue = ++poChar; /* skip ';' */
     415              13 :     iValueLength = 0;
     416            1177 :     while (*poChar != '\0') {
     417            1151 :         iValueLength++;
     418            1151 :         poChar++;
     419                 :     }
     420                 : 
     421              13 :     pszValue = (char *) CPLMalloc(iValueLength + 1);
     422              13 :     strncpy(pszValue, poValue, iValueLength);
     423              13 :     pszValue[iValueLength] = '\0';
     424                 : 
     425              13 :     poInfo[pszKey] = pszValue;
     426                 : 
     427              13 :     if (EQUAL(pszKey, "CODEPAGE")) {
     428               1 :         if (!EQUAL(pszValue, "\"WE8ISO8859P2\""))
     429               0 :             m_bLatin2 = FALSE;
     430                 :     }
     431                 : 
     432              13 :     CPLFree(pszKey);
     433              13 :     CPLFree(pszValue);
     434                 : }
     435                 : 
     436                 : /*!
     437                 :   \brief Get info
     438                 : 
     439                 :   \param key key string
     440                 : 
     441                 :   \return pointer to value string or NULL if key not found
     442                 : */
     443               0 : const char *VFKReader::GetInfo(const char *key)
     444                 : {
     445               0 :     if (poInfo.find(key) == poInfo.end())
     446               0 :         return NULL;
     447                 : 
     448               0 :     return poInfo[key].c_str();
     449                 : }

Generated by: LCOV version 1.7