LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vdv - ogrvdvdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 892 920 97.0 %
Date: XXXX-XX-XX Functions: 42 42 100.0 %
Branches: 1062 1696 62.6 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  *
       3                 :            :  * Project:  VDV Translator
       4                 :            :  * Purpose:  Implements OGRVDVFDriver.
       5                 :            :  * Author:   Even Rouault, even.rouault at spatialys.com
       6                 :            :  *
       7                 :            :  ******************************************************************************
       8                 :            :  * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com>
       9                 :            :  *
      10                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a
      11                 :            :  * copy of this software and associated documentation files (the "Software"),
      12                 :            :  * to deal in the Software without restriction, including without limitation
      13                 :            :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14                 :            :  * and/or sell copies of the Software, and to permit persons to whom the
      15                 :            :  * Software is furnished to do so, subject to the following conditions:
      16                 :            :  *
      17                 :            :  * The above copyright notice and this permission notice shall be included
      18                 :            :  * in all copies or substantial portions of the Software.
      19                 :            :  *
      20                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21                 :            :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23                 :            :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25                 :            :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26                 :            :  * DEALINGS IN THE SOFTWARE.
      27                 :            :  ****************************************************************************/
      28                 :            : 
      29                 :            : #include "ogr_vdv.h"
      30                 :            : #include "cpl_conv.h"
      31                 :            : #include "cpl_time.h"
      32                 :            : #include <map>
      33                 :            : 
      34                 :            : CPL_CVSID("$Id$");
      35                 :            : 
      36                 :            : #ifndef STARTS_WITH_CI
      37                 :            : #define STARTS_WITH(a,b)               (strncmp(a,b,strlen(b)) == 0)
      38                 :            : #define STARTS_WITH_CI(a,b)            EQUALN(a,b,strlen(b))
      39                 :            : #endif
      40                 :            : 
      41                 :            : typedef enum
      42                 :            : {
      43                 :            :     LAYER_OTHER,
      44                 :            :     LAYER_NODE,
      45                 :            :     LAYER_LINK,
      46                 :            :     LAYER_LINKCOORDINATE
      47                 :            : } IDFLayerType;
      48                 :            : 
      49                 :            : /************************************************************************/
      50                 :            : /*                          OGRVDVParseAtrFrm()                         */
      51                 :            : /************************************************************************/
      52                 :            : 
      53                 :          1 : static void OGRVDVParseAtrFrm(OGRFeatureDefn* poFeatureDefn,
      54                 :            :                               char** papszAtr,
      55                 :            :                               char** papszFrm)
      56                 :            : {
      57         [ +  + ]:          1 :     for(int i=0; papszAtr[i]; i++)
      58                 :            :     {
      59                 :          1 :         OGRFieldType eType = OFTString;
      60                 :          1 :         int nWidth = 0;
      61                 :          1 :         OGRFieldSubType eSubType = OFSTNone;
      62         [ +  + ]:          1 :         if( STARTS_WITH_CI(papszFrm[i], "decimal") )
      63                 :            :         {
      64         [ +  - ]:          1 :             if( papszFrm[i][strlen("decimal")] == '(' )
      65                 :            :             {
      66   [ +  +  +  - ]:          1 :                 if( strchr(papszFrm[i], ',') &&
      67                 :          1 :                     atoi(strchr(papszFrm[i], ',')+1) > 0 )
      68                 :            :                 {
      69                 :          1 :                     eType = OFTReal;
      70                 :            :                 }
      71                 :            :                 else
      72                 :            :                 {
      73                 :          1 :                     nWidth = atoi(papszFrm[i] + strlen("decimal") + 1);
      74         [ +  + ]:          1 :                     if( nWidth >= 10 )
      75                 :          1 :                         eType = OFTInteger64;
      76                 :            :                     else
      77                 :          1 :                         eType = OFTInteger;
      78                 :            :                 }
      79                 :            :             }
      80                 :            :             else
      81                 :          0 :                 eType = OFTInteger;
      82                 :            :         }
      83         [ +  + ]:          1 :         else if( STARTS_WITH_CI(papszFrm[i], "num") )
      84                 :            :         {
      85         [ +  - ]:          1 :             if( papszFrm[i][strlen("num")] == '[' )
      86                 :            :             {
      87   [ +  -  -  + ]:          1 :                 if( strchr(papszFrm[i], '.') &&
      88                 :          1 :                     atoi(strchr(papszFrm[i], '.')+1) > 0 )
      89                 :            :                 {
      90                 :          0 :                     eType = OFTReal;
      91                 :            :                 }
      92                 :            :                 else
      93                 :            :                 {
      94                 :          1 :                     nWidth = atoi(papszFrm[i] + strlen("num") + 1);
      95                 :          1 :                     nWidth += 1; /* VDV-451 width is without sign */
      96         [ +  + ]:          1 :                     if( nWidth >= 10 )
      97                 :          1 :                         eType = OFTInteger64;
      98                 :            :                     else
      99                 :          1 :                         eType = OFTInteger;
     100                 :            :                 }
     101                 :            :             }
     102                 :            :             else
     103                 :          0 :                 eType = OFTInteger;
     104                 :            :         }
     105         [ +  + ]:          1 :         else if( STARTS_WITH_CI(papszFrm[i], "char") )
     106                 :            :         {
     107         [ +  - ]:          1 :             if( papszFrm[i][strlen("char")] == '[' )
     108                 :            :             {
     109                 :          1 :                 nWidth = atoi(papszFrm[i] + strlen("char") + 1);
     110                 :            :             }
     111                 :            :         }
     112         [ +  + ]:          1 :         else if( STARTS_WITH_CI(papszFrm[i], "boolean") )
     113                 :            :         {
     114                 :          1 :             eType = OFTInteger;
     115                 :          1 :             eSubType = OFSTBoolean;
     116                 :            :         }
     117                 :          1 :         OGRFieldDefn oFieldDefn(papszAtr[i], eType);
     118         [ +  - ]:          1 :         oFieldDefn.SetSubType(eSubType);
     119         [ +  - ]:          1 :         oFieldDefn.SetWidth(nWidth);
     120         [ +  - ]:          1 :         poFeatureDefn->AddFieldDefn(&oFieldDefn);
     121                 :          1 :     }
     122                 :          1 : }
     123                 :            : 
     124                 :            : /************************************************************************/
     125                 :            : /*                           OGRIDFDataSource()                         */
     126                 :            : /************************************************************************/
     127                 :            : 
     128                 :          1 : OGRIDFDataSource::OGRIDFDataSource(VSILFILE* fpLIn) :
     129                 :            :     m_fpL(fpLIn),
     130                 :            :     m_bHasParsed(false),
     131                 :          1 :     m_poMemDS(NULL)
     132                 :          1 : {}
     133                 :            : 
     134                 :            : /************************************************************************/
     135                 :            : /*                          ~OGRIDFDataSource()                         */
     136                 :            : /************************************************************************/
     137                 :            : 
     138                 :          1 : OGRIDFDataSource::~OGRIDFDataSource()
     139                 :            : {
     140 [ +  - ][ +  - ]:          1 :     delete m_poMemDS;
     141         [ +  - ]:          1 :     if( m_fpL )
     142         [ +  - ]:          1 :         VSIFCloseL(m_fpL);
     143         [ -  + ]:          1 : }
     144                 :            : 
     145                 :            : /************************************************************************/
     146                 :            : /*                                Parse()                               */
     147                 :            : /************************************************************************/
     148                 :            : 
     149                 :          1 : void OGRIDFDataSource::Parse()
     150                 :            : {
     151                 :          1 :     m_bHasParsed = true;
     152                 :          1 :     GDALDriver* poMemDRV = (GDALDriver*)GDALGetDriverByName("MEMORY");
     153         [ -  + ]:          1 :     if( poMemDRV == NULL )
     154                 :          1 :         return;
     155                 :          1 :     m_poMemDS = poMemDRV->Create("", 0, 0, 0, GDT_Unknown, NULL);
     156                 :          1 :     OGRLayer* poCurLayer = NULL;
     157                 :          1 :     std::map<GIntBig, std::pair<double,double> > oMapNode; // map from NODE_ID to (X,Y)
     158         [ +  - ]:          1 :     std::map<GIntBig, OGRLineString*> oMapLinkCoordinate; // map from LINK_ID to OGRLineString*
     159 [ +  - ][ +  - ]:          1 :     CPLString osTablename, osAtr, osFrm;
                 [ +  - ]
     160                 :          1 :     int iX = -1, iY = -1;
     161                 :          1 :     bool bAdvertizeUTF8 = false;
     162                 :          1 :     bool bRecodeFromLatin1 = false;
     163                 :          1 :     int iNodeID = -1;
     164                 :          1 :     int iLinkID = -1;
     165                 :          1 :     int iFromNode = -1;
     166                 :          1 :     int iToNode = -1;
     167                 :          1 :     IDFLayerType eLayerType = LAYER_OTHER;
     168                 :            : 
     169                 :            :     // We assume that layers are in the order Node, Link, LinkCoordinate
     170                 :            : 
     171                 :          1 :     while( true )
     172                 :            :     {
     173         [ +  - ]:          1 :         const char* pszLine = CPLReadLineL(m_fpL);
     174         [ +  + ]:          1 :         if( pszLine == NULL )
     175                 :          1 :             break;
     176                 :            : 
     177         [ +  + ]:          1 :         if( strcmp(pszLine, "chs;ISO_LATIN_1") == 0)
     178                 :            :         {
     179                 :          1 :             bAdvertizeUTF8 = true;
     180                 :          1 :             bRecodeFromLatin1 = true;
     181                 :            :         }
     182         [ +  + ]:          1 :         else if( STARTS_WITH(pszLine, "tbl;") )
     183                 :            :         {
     184                 :          1 :             poCurLayer = NULL;
     185 [ +  - ][ +  - ]:          1 :             osTablename = pszLine + 4;
                 [ +  - ]
     186 [ +  - ][ +  - ]:          1 :             osAtr = "";
                 [ +  - ]
     187 [ +  - ][ +  - ]:          1 :             osFrm = "";
                 [ +  - ]
     188                 :          1 :             iX = iY = iNodeID = iLinkID = iFromNode = iToNode = -1;
     189                 :          1 :             eLayerType = LAYER_OTHER;
     190                 :            :         }
     191         [ +  + ]:          1 :         else if( STARTS_WITH(pszLine, "atr;") )
     192                 :            :         {
     193 [ +  - ][ +  - ]:          1 :             osAtr = pszLine + 4;
                 [ +  - ]
     194         [ +  - ]:          1 :             osAtr.Trim();
     195                 :            :         }
     196         [ +  + ]:          1 :         else if( STARTS_WITH(pszLine, "frm;") )
     197                 :            :         {
     198 [ +  - ][ +  - ]:          1 :             osFrm = pszLine + 4;
                 [ +  - ]
     199         [ +  - ]:          1 :             osFrm.Trim();
     200                 :            :         }
     201         [ +  + ]:          1 :         else if( STARTS_WITH(pszLine, "rec;") )
     202                 :            :         {
     203         [ +  + ]:          1 :             if( poCurLayer == NULL )
     204                 :            :             {
     205                 :            :                 char** papszAtr = CSLTokenizeString2(osAtr,";",
     206 [ +  - ][ +  - ]:          1 :                         CSLT_ALLOWEMPTYTOKENS|CSLT_STRIPLEADSPACES|CSLT_STRIPENDSPACES);
     207                 :            :                 char** papszFrm = CSLTokenizeString2(osFrm,";",
     208 [ +  - ][ +  - ]:          1 :                         CSLT_ALLOWEMPTYTOKENS|CSLT_STRIPLEADSPACES|CSLT_STRIPENDSPACES);
     209                 :          1 :                 char* apszOptions[2] = { NULL, NULL };
     210         [ +  - ]:          1 :                 if( bAdvertizeUTF8 )
     211                 :          1 :                     apszOptions[0] = (char*)"ADVERTIZE_UTF8=YES";
     212                 :            : 
     213 [ +  - ][ +  + ]:          1 :                 if( EQUAL(osTablename, "Node") &&
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  + ]
     214                 :            :                     (iX = CSLFindString(papszAtr, "X")) >= 0 &&
     215                 :            :                     (iY = CSLFindString(papszAtr, "Y")) >= 0 )
     216                 :            :                 {
     217                 :          1 :                     eLayerType = LAYER_NODE;
     218         [ +  - ]:          1 :                     iNodeID = CSLFindString(papszAtr, "NODE_ID");
     219 [ +  - ][ +  - ]:          1 :                     OGRSpatialReference* poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
     220 [ +  - ][ +  - ]:          1 :                     poCurLayer = m_poMemDS->CreateLayer(osTablename, poSRS, wkbPoint, apszOptions);
     221         [ +  - ]:          1 :                     poSRS->Release();
     222                 :            :                 }
     223 [ +  - ][ +  + ]:          1 :                 else if( EQUAL(osTablename, "Link") &&
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  + ]
     224                 :            :                         (iLinkID = CSLFindString(papszAtr, "LINK_ID")) >= 0 &&
     225                 :            :                         ((iFromNode = CSLFindString(papszAtr, "FROM_NODE")) >= 0) &&
     226                 :            :                         ((iToNode = CSLFindString(papszAtr, "TO_NODE")) >= 0) )
     227                 :            :                 {
     228                 :          1 :                     eLayerType = LAYER_LINK;
     229 [ +  - ][ +  - ]:          1 :                     OGRSpatialReference* poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
     230 [ +  - ][ +  - ]:          1 :                     poCurLayer = m_poMemDS->CreateLayer(osTablename, poSRS, wkbLineString, apszOptions);
     231         [ +  - ]:          1 :                     poSRS->Release();
     232                 :            :                 }
     233 [ +  - ][ +  + ]:          1 :                 else if( EQUAL(osTablename, "LinkCoordinate") &&
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
     234                 :            :                         (iLinkID = CSLFindString(papszAtr, "LINK_ID")) >= 0 &&
     235         [ +  - ]:          1 :                         CSLFindString(papszAtr, "COUNT") >= 0 &&
     236                 :            :                         (iX = CSLFindString(papszAtr, "X")) >= 0 &&
     237                 :            :                         (iY = CSLFindString(papszAtr, "Y")) >= 0 )
     238                 :            :                 {
     239                 :          1 :                     eLayerType = LAYER_LINKCOORDINATE;
     240 [ +  - ][ +  - ]:          1 :                     OGRSpatialReference* poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
     241 [ +  - ][ +  - ]:          1 :                     poCurLayer = m_poMemDS->CreateLayer(osTablename, poSRS, wkbPoint, apszOptions);
     242         [ +  - ]:          1 :                     poSRS->Release();
     243                 :            :                 }
     244                 :            :                 else
     245                 :            :                 {
     246 [ +  - ][ +  - ]:          1 :                     poCurLayer = m_poMemDS->CreateLayer(osTablename, NULL, wkbNone, apszOptions);
     247                 :            :                 }
     248                 :            : 
     249 [ +  - ][ +  - ]:          1 :                 if( !osAtr.empty() && CSLCount(papszAtr) == CSLCount(papszFrm) )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     250                 :            :                 {
     251                 :            :                     /* Note: we use AddFieldDefn() directly on the layer defn */
     252                 :            :                     /* This works with the current implementation of the MEM driver */
     253                 :            :                     /* but beware of future changes... */
     254 [ +  - ][ +  - ]:          1 :                     OGRVDVParseAtrFrm(poCurLayer->GetLayerDefn(), papszAtr, papszFrm);
     255                 :            :                 }
     256         [ +  - ]:          1 :                 CSLDestroy(papszAtr);
     257         [ +  - ]:          1 :                 CSLDestroy(papszFrm);
     258                 :            :             }
     259                 :            : 
     260                 :          1 :             OGRErr eErr = OGRERR_NONE;
     261         [ +  - ]:          1 :             char** papszTokens = CSLTokenizeStringComplex(pszLine + 4,";",TRUE,TRUE);
     262         [ +  - ]:          1 :             OGRFeatureDefn* poFDefn = poCurLayer->GetLayerDefn();
     263 [ +  - ][ +  - ]:          1 :             OGRFeature* poFeature = new OGRFeature(poFDefn);
     264 [ +  - ][ +  + ]:          1 :             for(int i=0; i < poFDefn->GetFieldCount() && papszTokens[i] != NULL ;i++)
         [ +  - ][ +  + ]
     265                 :            :             {
     266         [ +  - ]:          1 :                 if( papszTokens[i][0] )
     267                 :            :                 {
     268 [ +  - ][ +  + ]:          1 :                     if( bRecodeFromLatin1 &&
                 [ +  + ]
     269 [ +  - ][ +  - ]:          1 :                         poFDefn->GetFieldDefn(i)->GetType() == OFTString )
     270                 :            :                     {
     271                 :          1 :                         char* pszRecoded = CPLRecode(papszTokens[i],
     272         [ +  - ]:          1 :                                             CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
     273         [ +  - ]:          1 :                         poFeature->SetField(i, pszRecoded);
     274         [ +  - ]:          1 :                         CPLFree(pszRecoded);
     275                 :            :                     }
     276                 :            :                     else
     277                 :            :                     {
     278         [ +  - ]:          1 :                         poFeature->SetField(i, papszTokens[i]);
     279                 :            :                     }
     280                 :            :                 }
     281                 :            :             }
     282                 :            : 
     283 [ +  + ][ +  - ]:          1 :             if( eLayerType == LAYER_NODE && iX >= 0 && iY >= 0 && iNodeID >= 0 )
         [ +  - ][ +  - ]
     284                 :            :             {
     285         [ +  - ]:          1 :                 double dfX = poFeature->GetFieldAsDouble(iX);
     286         [ +  - ]:          1 :                 double dfY = poFeature->GetFieldAsDouble(iY);
     287 [ +  - ][ +  - ]:          1 :                 oMapNode[ poFeature->GetFieldAsInteger64(iNodeID) ] =
     288         [ +  - ]:          1 :                                         std::pair<double,double>(dfX, dfY);
     289 [ +  - ][ +  - ]:          1 :                 OGRGeometry* poGeom = new OGRPoint( dfX, dfY );
     290 [ +  - ][ +  - ]:          1 :                 poGeom->assignSpatialReference(poFDefn->GetGeomFieldDefn(0)->GetSpatialRef());
                 [ +  - ]
     291         [ +  - ]:          1 :                 poFeature->SetGeometryDirectly(poGeom);
     292                 :            :             }
     293 [ +  + ][ +  - ]:          1 :             else if( eLayerType == LAYER_LINK && iFromNode >= 0 &&
                 [ +  - ]
     294                 :            :                      iToNode >= 0 )
     295                 :            :             {
     296         [ +  - ]:          1 :                 GIntBig nFromNode = poFeature->GetFieldAsInteger64(iFromNode);
     297         [ +  - ]:          1 :                 GIntBig nToNode = poFeature->GetFieldAsInteger64(iToNode);
     298                 :            :                 std::map<GIntBig, std::pair<double,double> >::iterator
     299         [ +  - ]:          1 :                                         oIterFrom = oMapNode.find(nFromNode);
     300                 :            :                 std::map<GIntBig, std::pair<double,double> >::iterator
     301         [ +  - ]:          1 :                                         oIterTo = oMapNode.find(nToNode);
     302 [ +  - ][ +  - ]:          1 :                 if( oIterFrom != oMapNode.end() && oIterTo != oMapNode.end() )
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
                 [ +  + ]
     303                 :            :                 {
     304 [ +  - ][ +  - ]:          1 :                     OGRLineString* poLS = new OGRLineString();
     305 [ +  - ][ +  - ]:          1 :                     poLS->addPoint( oIterFrom->second.first, oIterFrom->second.second );
                 [ +  - ]
     306 [ +  - ][ +  - ]:          1 :                     poLS->addPoint( oIterTo->second.first, oIterTo->second.second );
                 [ +  - ]
     307 [ +  - ][ +  - ]:          1 :                     poLS->assignSpatialReference(poFDefn->GetGeomFieldDefn(0)->GetSpatialRef());
                 [ +  - ]
     308         [ +  - ]:          1 :                     poFeature->SetGeometryDirectly(poLS);
     309                 :          1 :                 }
     310                 :            :             }
     311 [ +  + ][ +  - ]:          1 :             else if( eLayerType == LAYER_LINKCOORDINATE &&
         [ +  - ][ +  - ]
     312                 :            :                      iX >= 0 && iY >= 0 && iLinkID >= 0 )
     313                 :            :             {
     314         [ +  - ]:          1 :                 double dfX = poFeature->GetFieldAsDouble(iX);
     315         [ +  - ]:          1 :                 double dfY = poFeature->GetFieldAsDouble(iY);
     316 [ +  - ][ +  - ]:          1 :                 OGRGeometry* poGeom = new OGRPoint( dfX, dfY );
     317 [ +  - ][ +  - ]:          1 :                 poGeom->assignSpatialReference(poFDefn->GetGeomFieldDefn(0)->GetSpatialRef());
                 [ +  - ]
     318         [ +  - ]:          1 :                 poFeature->SetGeometryDirectly(poGeom);
     319                 :            : 
     320         [ +  - ]:          1 :                 GIntBig nCurLinkID = poFeature->GetFieldAsInteger64(iLinkID);
     321                 :            :                 std::map<GIntBig, OGRLineString*>::iterator
     322         [ +  - ]:          1 :                     oMapLinkCoordinateIter = oMapLinkCoordinate.find(nCurLinkID);
     323 [ +  - ][ +  - ]:          1 :                 if( oMapLinkCoordinateIter == oMapLinkCoordinate.end() )
                 [ +  + ]
     324                 :            :                 {
     325 [ +  - ][ +  - ]:          1 :                     OGRLineString* poLS = new OGRLineString();
     326         [ +  - ]:          1 :                     poLS->addPoint(dfX, dfY);
     327         [ +  - ]:          1 :                     oMapLinkCoordinate[nCurLinkID] = poLS;
     328                 :            :                 }
     329                 :            :                 else
     330                 :            :                 {
     331 [ +  - ][ +  - ]:          1 :                     oMapLinkCoordinateIter->second->addPoint(dfX, dfY);
     332                 :            :                 }
     333                 :            :             }
     334         [ +  - ]:          1 :             eErr = poCurLayer->CreateFeature(poFeature);
     335 [ +  - ][ +  - ]:          1 :             delete poFeature;
     336                 :            : 
     337         [ +  - ]:          1 :             CSLDestroy(papszTokens);
     338                 :            : 
     339         [ -  + ]:          1 :             if( eErr == OGRERR_FAILURE )
     340                 :          0 :                 break;
     341                 :            :         }
     342                 :            :     }
     343                 :            : 
     344                 :            :     // Patch Link geometries with the intermediate points of LinkCoordinate
     345         [ +  - ]:          1 :     OGRLayer* poLinkLyr = m_poMemDS->GetLayerByName("Link");
     346         [ +  - ]:          1 :     if( poLinkLyr )
     347                 :            :     {
     348 [ +  - ][ +  - ]:          1 :         iLinkID = poLinkLyr->GetLayerDefn()->GetFieldIndex("LINK_ID");
     349         [ +  - ]:          1 :         if( iLinkID >= 0 )
     350                 :            :         {
     351         [ +  - ]:          1 :             poLinkLyr->ResetReading();
     352                 :            :             OGRSpatialReference* poSRS =
     353 [ +  - ][ +  - ]:          1 :                 poLinkLyr->GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef();
                 [ +  - ]
     354                 :          1 :             OGRFeature* poFeat = NULL;
     355 [ +  - ][ +  + ]:          1 :             while( (poFeat = poLinkLyr->GetNextFeature()) != NULL )
     356                 :            :             {
     357         [ +  - ]:          1 :                 GIntBig nLinkID = poFeat->GetFieldAsInteger64(iLinkID);
     358                 :            :                 std::map<GIntBig, OGRLineString*>::iterator
     359         [ +  - ]:          1 :                     oMapLinkCoordinateIter = oMapLinkCoordinate.find(nLinkID);
     360         [ +  - ]:          1 :                 OGRLineString* poLS = (OGRLineString*)poFeat->GetGeometryRef();
     361 [ +  + ][ +  - ]:          1 :                 if( poLS != NULL && oMapLinkCoordinateIter != oMapLinkCoordinate.end() )
         [ +  - ][ +  + ]
                 [ +  + ]
     362                 :            :                 {
     363         [ +  - ]:          1 :                     OGRLineString* poLSIntermediate = oMapLinkCoordinateIter->second;
     364 [ +  - ][ +  - ]:          1 :                     OGRLineString* poLSNew = new OGRLineString();
     365 [ +  - ][ +  - ]:          1 :                     poLSNew->addPoint(poLS->getX(0), poLS->getY(0));
                 [ +  - ]
     366 [ +  - ][ +  + ]:          1 :                     for(int i=0;i<poLSIntermediate->getNumPoints();i++)
     367                 :            :                     {
     368                 :            :                         poLSNew->addPoint(poLSIntermediate->getX(i),
     369 [ +  - ][ +  - ]:          1 :                                           poLSIntermediate->getY(i));
                 [ +  - ]
     370                 :            :                     }
     371 [ +  - ][ +  - ]:          1 :                     poLSNew->addPoint(poLS->getX(1), poLS->getY(1));
                 [ +  - ]
     372         [ +  - ]:          1 :                     poLSNew->assignSpatialReference(poSRS);
     373         [ +  - ]:          1 :                     poFeat->SetGeometryDirectly(poLSNew);
     374         [ +  - ]:          1 :                     CPL_IGNORE_RET_VAL(poLinkLyr->SetFeature(poFeat));
     375                 :            :                 }
     376 [ +  - ][ +  - ]:          1 :                 delete poFeat;
     377                 :            :             }
     378         [ +  - ]:          1 :             poLinkLyr->ResetReading();
     379                 :            :         }
     380                 :            :     }
     381                 :            : 
     382                 :            :     std::map<GIntBig, OGRLineString*>::iterator oMapLinkCoordinateIter =
     383         [ +  - ]:          1 :                                                     oMapLinkCoordinate.begin();
     384 [ +  - ][ +  - ]:          1 :     for(; oMapLinkCoordinateIter != oMapLinkCoordinate.end(); ++oMapLinkCoordinateIter)
         [ +  - ][ +  + ]
     385 [ +  - ][ +  - ]:          1 :         delete oMapLinkCoordinateIter->second;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     386                 :            : }
     387                 :            : 
     388                 :            : /************************************************************************/
     389                 :            : /*                           GetLayerCount()                            */
     390                 :            : /************************************************************************/
     391                 :            : 
     392                 :          1 : int OGRIDFDataSource::GetLayerCount()
     393                 :            : {
     394         [ +  + ]:          1 :     if( !m_bHasParsed )
     395                 :          1 :         Parse();
     396         [ -  + ]:          1 :     if( m_poMemDS == NULL )
     397                 :          0 :         return 0;
     398                 :          1 :     return m_poMemDS->GetLayerCount();
     399                 :            : }
     400                 :            : 
     401                 :            : /************************************************************************/
     402                 :            : /*                              GetLayer()                              */
     403                 :            : /************************************************************************/
     404                 :            : 
     405                 :          1 : OGRLayer* OGRIDFDataSource::GetLayer( int iLayer )
     406                 :            : {
     407 [ +  + ][ +  + ]:          1 :     if( iLayer < 0 || iLayer >= GetLayerCount() )
                 [ +  + ]
     408                 :          1 :         return NULL;
     409         [ -  + ]:          1 :     if( m_poMemDS == NULL )
     410                 :          0 :         return NULL;
     411                 :          1 :     return m_poMemDS->GetLayer(iLayer);
     412                 :            : }
     413                 :            : 
     414                 :            : /************************************************************************/
     415                 :            : /*                           OGRVDVDataSource()                         */
     416                 :            : /************************************************************************/
     417                 :            : 
     418                 :          1 : OGRVDVDataSource::OGRVDVDataSource(const char* pszFilename,
     419                 :            :                                    VSILFILE* fpL,
     420                 :            :                                    bool bUpdate,
     421                 :            :                                    bool bSingleFile,
     422                 :            :                                    bool bNew) :
     423                 :            :     m_osFilename(pszFilename),
     424                 :            :     m_fpL(fpL),
     425                 :            :     m_bUpdate(bUpdate),
     426                 :            :     m_bSingleFile(bSingleFile),
     427                 :            :     m_bNew(bNew),
     428                 :            :     m_bLayersDetected(bNew || fpL == NULL),
     429                 :            :     m_nLayerCount(0),
     430                 :            :     m_papoLayers(NULL),
     431                 :            :     m_poCurrentWriterLayer(NULL),
     432                 :            :     m_bMustWriteEof(false),
     433 [ +  - ][ +  + ]:          1 :     m_bVDV452Loaded(false)
         [ +  + ][ +  - ]
     434                 :          1 : {}
     435                 :            : 
     436                 :            : /************************************************************************/
     437                 :            : /*                          ~OGRVDVDataSource()                         */
     438                 :            : /************************************************************************/
     439                 :            : 
     440 [ +  - ][ +  - ]:          1 : OGRVDVDataSource::~OGRVDVDataSource()
     441                 :            : {
     442         [ +  + ]:          1 :     if( m_poCurrentWriterLayer )
     443                 :            :     {
     444         [ +  - ]:          1 :         m_poCurrentWriterLayer->StopAsCurrentLayer();
     445                 :          1 :         m_poCurrentWriterLayer = NULL;
     446                 :            :     }
     447                 :            : 
     448         [ +  + ]:          1 :     for(int i=0;i<m_nLayerCount;i++)
     449 [ +  - ][ +  - ]:          1 :         delete m_papoLayers[i];
     450         [ +  - ]:          1 :     CPLFree(m_papoLayers);
     451                 :            : 
     452                 :            :     // Close after destroying layers since they might use it (single file write)
     453         [ +  + ]:          1 :     if( m_fpL )
     454                 :            :     {
     455         [ +  + ]:          1 :         if( m_bMustWriteEof )
     456                 :            :         {
     457         [ +  - ]:          1 :             VSIFPrintfL( m_fpL, "eof; %d\n", m_nLayerCount );
     458                 :            :         }
     459         [ +  - ]:          1 :         VSIFCloseL(m_fpL);
     460                 :            :     }
     461         [ -  + ]:          1 : }
     462                 :            : 
     463                 :            : /************************************************************************/
     464                 :            : /*                           GetLayerCount()                            */
     465                 :            : /************************************************************************/
     466                 :            : 
     467                 :          1 : int OGRVDVDataSource::GetLayerCount()
     468                 :            : {
     469         [ +  + ]:          1 :     if( !m_bLayersDetected )
     470                 :          1 :         DetectLayers();
     471                 :          1 :     return m_nLayerCount;
     472                 :            : }
     473                 :            : 
     474                 :            : /************************************************************************/
     475                 :            : /*                              GetLayer()                              */
     476                 :            : /************************************************************************/
     477                 :            : 
     478                 :          1 : OGRLayer* OGRVDVDataSource::GetLayer( int iLayer )
     479                 :            : {
     480 [ +  + ][ +  + ]:          1 :     if( iLayer < 0 || iLayer >= GetLayerCount() )
                 [ +  + ]
     481                 :          1 :         return NULL;
     482                 :          1 :     return m_papoLayers[iLayer];
     483                 :            : }
     484                 :            : 
     485                 :            : /************************************************************************/
     486                 :            : /*                         DetectLayers()                               */
     487                 :            : /************************************************************************/
     488                 :            : 
     489                 :          1 : void OGRVDVDataSource::DetectLayers()
     490                 :            : {
     491                 :          1 :     m_bLayersDetected = true;
     492                 :            : 
     493                 :            :     char szBuffer[1+1024+1];
     494                 :          1 :     char chNextExpected = 't';
     495                 :          1 :     char chNextExpected2 = 'r';
     496                 :          1 :     char chNextExpected3 = 'e';
     497                 :          1 :     bool bInTableName = false;
     498                 :          1 :     CPLString osTableName;
     499                 :          1 :     GIntBig nFeatureCount = 0;
     500                 :          1 :     vsi_l_offset nStartOffset = 0;
     501                 :          1 :     OGRVDVLayer* poLayer = NULL;
     502                 :          1 :     bool bFirstBuffer = true;
     503                 :          1 :     bool bRecodeFromLatin1 = false;
     504                 :            : 
     505         [ +  - ]:          1 :     VSIFSeekL(m_fpL, 0, SEEK_SET);
     506                 :            : 
     507                 :          0 :     while( true )
     508                 :            :     {
     509         [ +  - ]:          1 :         size_t nRead = VSIFReadL(szBuffer, 1, 1024, m_fpL);
     510                 :          1 :         szBuffer[nRead] = '\0';
     511         [ +  - ]:          1 :         if( bFirstBuffer )
     512                 :            :         {
     513                 :          1 :             const char* pszChs = strstr(szBuffer, "\nchs;");
     514         [ +  + ]:          1 :             if( pszChs )
     515                 :            :             {
     516                 :          1 :                 pszChs += 5;
     517         [ +  - ]:          1 :                 CPLString osChs;
     518 [ +  - ][ +  - ]:          1 :                 for(; *pszChs != '\0' && *pszChs != '\r' && *pszChs != '\n';
         [ +  + ][ +  + ]
     519                 :            :                     ++pszChs)
     520                 :            :                 {
     521 [ +  + ][ +  + ]:          1 :                     if( *pszChs != ' ' && *pszChs != '"' )
     522         [ +  - ]:          1 :                         osChs += *pszChs;
     523                 :            :                 }
     524         [ +  - ]:          1 :                 bRecodeFromLatin1 = EQUAL(osChs, "ISO8859-1") ||
     525 [ -  + ][ #  # ]:          1 :                                     EQUAL(osChs, "ISO_LATIN_1");
         [ #  # ][ +  - ]
     526                 :            :             }
     527                 :          1 :             bFirstBuffer = false;
     528                 :            :         }
     529         [ +  + ]:          1 :         for(size_t i=0;i<nRead;i++)
     530                 :            :         {
     531         [ +  + ]:          1 :             if( bInTableName )
     532                 :            :             {
     533 [ +  - ][ +  + ]:          1 :                 if( szBuffer[i] == '\r' || szBuffer[i] == '\n' )
     534                 :            :                 {
     535                 :          1 :                     bInTableName = false;
     536                 :            :                     poLayer = new OGRVDVLayer(osTableName,
     537                 :            :                                               m_fpL,
     538                 :            :                                               false,
     539                 :            :                                               bRecodeFromLatin1,
     540 [ +  - ][ +  - ]:          1 :                                               nStartOffset);
     541                 :            :                     m_papoLayers = static_cast<OGRLayer**>(CPLRealloc(
     542         [ +  - ]:          1 :                         m_papoLayers, sizeof(OGRLayer*) * (m_nLayerCount + 1) ));
     543                 :          1 :                     m_papoLayers[m_nLayerCount] = poLayer;
     544                 :          1 :                     m_nLayerCount ++;
     545                 :            :                 }
     546         [ +  + ]:          1 :                 else if( szBuffer[i] != ' ' )
     547                 :            :                 {
     548         [ +  - ]:          1 :                     osTableName += szBuffer[i];
     549                 :          1 :                     continue;
     550                 :            :                 }
     551                 :            :             }
     552                 :            : 
     553                 :            :             // Reset state on end of line characters
     554 [ +  + ][ -  + ]:          1 :             if( szBuffer[i] == '\n' || szBuffer[i] == '\r' )
     555                 :            :             {
     556                 :          1 :                 chNextExpected = szBuffer[i];
     557                 :          1 :                 chNextExpected2 = szBuffer[i];
     558                 :          1 :                 chNextExpected3 = szBuffer[i];
     559                 :            :             }
     560                 :            : 
     561                 :            :             // Detect tbl;
     562         [ +  + ]:          1 :             if( szBuffer[i] == chNextExpected )
     563                 :            :             {
     564 [ +  + ][ -  + ]:          1 :                 if( chNextExpected == '\n' || chNextExpected == '\r' )
     565                 :          1 :                     chNextExpected = 't';
     566         [ +  + ]:          1 :                 else if( chNextExpected == 't' )
     567                 :          1 :                     chNextExpected = 'b';
     568         [ +  + ]:          1 :                 else if( chNextExpected == 'b' )
     569                 :          1 :                     chNextExpected = 'l';
     570         [ +  + ]:          1 :                 else if( chNextExpected == 'l' )
     571                 :          1 :                     chNextExpected = ';';
     572         [ +  - ]:          1 :                 else if( chNextExpected == ';' )
     573                 :            :                 {
     574         [ +  + ]:          1 :                     if( poLayer != NULL )
     575                 :          1 :                         poLayer->SetFeatureCount(nFeatureCount);
     576                 :          1 :                     poLayer = NULL;
     577                 :          1 :                     nFeatureCount = 0;
     578         [ +  - ]:          1 :                     nStartOffset = VSIFTellL(m_fpL) - nRead + i - 4 + 1;
     579                 :          1 :                     bInTableName = true;
     580         [ +  - ]:          1 :                     osTableName.resize(0);
     581                 :          1 :                     chNextExpected = 0;
     582                 :            :                 }
     583                 :            :             }
     584                 :            :             else
     585                 :          1 :                 chNextExpected = 0;
     586                 :            : 
     587                 :            :             // Detect rec;
     588         [ +  + ]:          1 :             if( szBuffer[i] == chNextExpected2 )
     589                 :            :             {
     590 [ +  + ][ -  + ]:          1 :                 if( chNextExpected2 == '\n' || chNextExpected2 == '\r' )
     591                 :          1 :                     chNextExpected2 = 'r';
     592         [ +  + ]:          1 :                 else if( chNextExpected2 == 'r' )
     593                 :          1 :                     chNextExpected2 = 'e';
     594         [ +  + ]:          1 :                 else if( chNextExpected2 == 'e' )
     595                 :          1 :                     chNextExpected2 = 'c';
     596         [ +  + ]:          1 :                 else if( chNextExpected2 == 'c' )
     597                 :          1 :                     chNextExpected2 = ';';
     598         [ +  - ]:          1 :                 else if( chNextExpected2 == ';' )
     599                 :            :                 {
     600                 :          1 :                     nFeatureCount ++;
     601                 :          1 :                     chNextExpected2 = 0;
     602                 :            :                 }
     603                 :            :             }
     604                 :            :             else
     605                 :          1 :                 chNextExpected2 = 0;
     606                 :            : 
     607                 :            :             // Detect end;
     608         [ +  + ]:          1 :             if( szBuffer[i] == chNextExpected3 )
     609                 :            :             {
     610 [ +  + ][ -  + ]:          1 :                 if( chNextExpected3 == '\n' || chNextExpected3 == '\r' )
     611                 :          1 :                     chNextExpected3 = 'e';
     612         [ +  + ]:          1 :                 else if( chNextExpected3 == 'e' )
     613                 :          1 :                     chNextExpected3 = 'n';
     614         [ +  + ]:          1 :                 else if( chNextExpected3 == 'n' )
     615                 :          1 :                     chNextExpected3 = 'd';
     616         [ +  + ]:          1 :                 else if( chNextExpected3 == 'd' )
     617                 :          1 :                     chNextExpected3 = ';';
     618         [ +  - ]:          1 :                 else if( chNextExpected3 == ';' )
     619                 :            :                 {
     620         [ +  - ]:          1 :                     if( poLayer != NULL )
     621                 :          1 :                         poLayer->SetFeatureCount(nFeatureCount);
     622                 :          1 :                     poLayer = NULL;
     623                 :          1 :                     chNextExpected3 = 0;
     624                 :            :                 }
     625                 :            :             }
     626                 :            :             else
     627                 :          1 :                 chNextExpected3 = 0;
     628                 :            :         }
     629         [ +  - ]:          1 :         if( nRead < 1024 )
     630                 :          1 :             break;
     631                 :            :     }
     632         [ +  + ]:          1 :     if( poLayer != NULL )
     633                 :          1 :         poLayer->SetFeatureCount(nFeatureCount);
     634                 :          1 : }
     635                 :            : 
     636                 :            : /************************************************************************/
     637                 :            : /*                           OGRVDVLayer()                              */
     638                 :            : /************************************************************************/
     639                 :            : 
     640                 :          1 : OGRVDVLayer::OGRVDVLayer(const CPLString& osTableName,
     641                 :            :                          VSILFILE* fpL,
     642                 :            :                          bool bOwnFP,
     643                 :            :                          bool bRecodeFromLatin1,
     644                 :            :                          vsi_l_offset nStartOffset) :
     645                 :            :     m_fpL(fpL),
     646                 :            :     m_bOwnFP(bOwnFP),
     647                 :            :     m_bRecodeFromLatin1(bRecodeFromLatin1),
     648                 :            :     m_nStartOffset(nStartOffset),
     649                 :            :     m_nCurOffset(0),
     650                 :            :     m_nTotalFeatureCount(0),
     651                 :            :     m_nFID(0),
     652                 :            :     m_bEOF(false),
     653                 :            :     m_iLongitudeVDV452(-1),
     654                 :          1 :     m_iLatitudeVDV452(-1)
     655                 :            : {
     656 [ +  - ][ +  - ]:          1 :     m_poFeatureDefn = new OGRFeatureDefn(osTableName);
                 [ +  - ]
     657         [ +  - ]:          1 :     m_poFeatureDefn->SetGeomType(wkbNone);
     658         [ +  - ]:          1 :     m_poFeatureDefn->Reference();
     659 [ +  - ][ +  - ]:          1 :     SetDescription(osTableName);
     660         [ +  - ]:          1 :     vsi_l_offset nCurOffset = VSIFTellL(fpL);
     661         [ +  - ]:          1 :     VSIFSeekL(m_fpL, m_nStartOffset, SEEK_SET);
     662 [ +  - ][ +  - ]:          1 :     CPLString osAtr, osFrm;
     663                 :            : 
     664                 :            :     /* skip until first tbl; */
     665                 :          1 :     bool bFoundTbl = false;
     666         [ +  - ]:          1 :     for(int i=0;i<20;i++)
     667                 :            :     {
     668         [ +  - ]:          1 :         const char* pszLine = CPLReadLineL(m_fpL);
     669         [ +  + ]:          1 :         if( pszLine == NULL )
     670                 :          1 :             break;
     671         [ +  + ]:          1 :         if( STARTS_WITH(pszLine, "chs;") )
     672                 :            :         {
     673         [ +  - ]:          1 :             CPLString osChs(pszLine+4);
     674         [ +  - ]:          1 :             osChs.Trim();
     675 [ +  - ][ +  - ]:          1 :             if( osChs.size() >= 2 && osChs[0] == '"' && osChs.back() == '"' )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     676 [ +  - ][ +  - ]:          1 :                 osChs = osChs.substr(1, osChs.size()-2);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     677         [ +  - ]:          1 :             m_bRecodeFromLatin1 = EQUAL(osChs, "ISO8859-1") ||
     678 [ -  + ][ #  # ]:          1 :                                   EQUAL(osChs, "ISO_LATIN_1");
         [ #  # ][ +  - ]
     679                 :            :         }
     680         [ +  + ]:          1 :         else if( STARTS_WITH(pszLine, "tbl;") )
     681                 :            :         {
     682         [ -  + ]:          1 :             if( bFoundTbl )
     683                 :          0 :                 break; /* shouldn't happen in correctly formed files */
     684                 :          1 :             bFoundTbl = true;
     685         [ +  - ]:          1 :             m_nStartOffset = VSIFTellL(fpL);
     686                 :            :         }
     687         [ +  + ]:          1 :         else if( STARTS_WITH(pszLine, "atr;") )
     688                 :            :         {
     689 [ +  - ][ +  - ]:          1 :             osAtr = pszLine + 4;
                 [ +  - ]
     690         [ +  - ]:          1 :             osAtr.Trim();
     691                 :            :         }
     692         [ +  + ]:          1 :         else if( STARTS_WITH(pszLine, "frm;") )
     693                 :            :         {
     694 [ +  - ][ +  - ]:          1 :             osFrm = pszLine + 4;
                 [ +  - ]
     695         [ +  - ]:          1 :             osFrm.Trim();
     696                 :            :         }
     697 [ +  + ][ +  + ]:          1 :         else if( STARTS_WITH(pszLine, "rec;") ||
     698                 :          1 :                  STARTS_WITH(pszLine, "end;") )
     699                 :          1 :             break;
     700                 :            :     }
     701         [ -  + ]:          1 :     if( !bFoundTbl )
     702         [ #  # ]:          0 :         CPLDebug("VDV", "Didn't find tbl; line");
     703                 :            : 
     704         [ +  - ]:          1 :     VSIFSeekL(m_fpL, nCurOffset, SEEK_SET);
     705 [ +  - ][ +  + ]:          1 :     if( !osAtr.empty() && !osFrm.empty() )
         [ +  - ][ +  - ]
                 [ +  + ]
     706                 :            :     {
     707                 :            :         char** papszAtr = CSLTokenizeString2(osAtr,";",
     708 [ +  - ][ +  - ]:          1 :                     CSLT_ALLOWEMPTYTOKENS|CSLT_STRIPLEADSPACES|CSLT_STRIPENDSPACES);
     709                 :            :         char** papszFrm = CSLTokenizeString2(osFrm,";",
     710 [ +  - ][ +  - ]:          1 :                     CSLT_ALLOWEMPTYTOKENS|CSLT_STRIPLEADSPACES|CSLT_STRIPENDSPACES);
     711 [ +  - ][ +  - ]:          1 :         if( CSLCount(papszAtr) == CSLCount(papszFrm) )
                 [ +  - ]
     712                 :            :         {
     713         [ +  - ]:          1 :             OGRVDVParseAtrFrm(m_poFeatureDefn, papszAtr, papszFrm);
     714                 :            :         }
     715         [ +  - ]:          1 :         CSLDestroy(papszAtr);
     716         [ +  - ]:          1 :         CSLDestroy(papszFrm);
     717                 :            :     }
     718                 :            : 
     719                 :            :     // Identify longitude, latitude columns of VDV-452 STOP table
     720 [ +  - ][ +  + ]:          1 :     if( EQUAL(osTableName, "STOP") ) /* English */
     721                 :            :     {
     722         [ +  - ]:          1 :         m_iLongitudeVDV452 = m_poFeatureDefn->GetFieldIndex("POINT_LONGITUDE");
     723         [ +  - ]:          1 :         m_iLatitudeVDV452 = m_poFeatureDefn->GetFieldIndex("POINT_LATITUDE");
     724                 :            :     }
     725 [ +  - ][ +  + ]:          1 :     else if( EQUAL(osTableName, "REC_ORT") ) /* German */
     726                 :            :     {
     727         [ +  - ]:          1 :         m_iLongitudeVDV452 = m_poFeatureDefn->GetFieldIndex("ORT_POS_LAENGE");
     728         [ +  - ]:          1 :         m_iLatitudeVDV452 = m_poFeatureDefn->GetFieldIndex("ORT_POS_BREITE");
     729                 :            :     }
     730 [ +  + ][ +  - ]:          1 :     if( m_iLongitudeVDV452 >= 0 && m_iLatitudeVDV452 >= 0 )
     731                 :            :     {
     732         [ +  - ]:          1 :         m_poFeatureDefn->SetGeomType(wkbPoint);
     733 [ +  - ][ +  - ]:          1 :         OGRSpatialReference* poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
     734 [ +  - ][ +  - ]:          1 :         m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
     735         [ +  - ]:          1 :         poSRS->Release();
     736                 :            :     }
     737                 :            :     else
     738 [ +  - ][ +  - ]:          1 :         m_iLongitudeVDV452 = m_iLatitudeVDV452 = -1;
     739                 :          1 : }
     740                 :            : 
     741                 :            : /************************************************************************/
     742                 :            : /*                          ~OGRVDVLayer()                              */
     743                 :            : /************************************************************************/
     744                 :            : 
     745                 :          1 : OGRVDVLayer::~OGRVDVLayer()
     746                 :            : {
     747         [ +  - ]:          1 :     m_poFeatureDefn->Release();
     748         [ +  + ]:          1 :     if( m_bOwnFP )
     749         [ +  - ]:          1 :         VSIFCloseL(m_fpL);
     750         [ -  + ]:          1 : }
     751                 :            : 
     752                 :            : /************************************************************************/
     753                 :            : /*                          ResetReading()                              */
     754                 :            : /************************************************************************/
     755                 :            : 
     756                 :          1 : void OGRVDVLayer::ResetReading()
     757                 :            : {
     758                 :          1 :     VSIFSeekL(m_fpL, m_nStartOffset, SEEK_SET);
     759                 :          1 :     m_nCurOffset = m_nStartOffset;
     760                 :          1 :     m_nFID = 1;
     761                 :          1 :     m_bEOF = false;
     762                 :          1 : }
     763                 :            : 
     764                 :            : /************************************************************************/
     765                 :            : /*                         OGRVDVUnescapeString()                       */
     766                 :            : /************************************************************************/
     767                 :            : 
     768                 :          1 : static CPLString OGRVDVUnescapeString(const char* pszValue)
     769                 :            : {
     770                 :          1 :     CPLString osRet;
     771         [ +  + ]:          1 :     for(; *pszValue != '\0'; ++pszValue )
     772                 :            :     {
     773 [ +  + ][ +  - ]:          1 :         if( *pszValue == '"' && pszValue[1] == '"' )
     774                 :            :         {
     775         [ +  - ]:          1 :             osRet += '"';
     776                 :          1 :             ++pszValue;
     777                 :            :         }
     778                 :            :         else
     779                 :            :         {
     780         [ +  - ]:          1 :             osRet += *pszValue;
     781                 :            :         }
     782                 :            :     }
     783                 :          1 :     return osRet;
     784                 :            : }
     785                 :            : 
     786                 :            : /************************************************************************/
     787                 :            : /*                          GetNextFeature()                            */
     788                 :            : /************************************************************************/
     789                 :            : 
     790                 :          1 : OGRFeature* OGRVDVLayer::GetNextFeature()
     791                 :            : {
     792         [ +  + ]:          1 :     if( m_nFID == 0 )
     793                 :          1 :         ResetReading();
     794                 :          1 :     VSIFSeekL(m_fpL, m_nCurOffset, SEEK_SET);
     795                 :          1 :     OGRFeature* poFeature = NULL;
     796         [ +  - ]:          1 :     while( !m_bEOF )
     797                 :            :     {
     798                 :          1 :         const char* pszLine = CPLReadLineL(m_fpL);
     799         [ -  + ]:          1 :         if( pszLine == NULL )
     800                 :          0 :             break;
     801 [ +  + ][ +  + ]:          1 :         if( strncmp(pszLine, "end;", 4) == 0 ||
     802                 :          1 :             strncmp(pszLine, "tbl;", 4) == 0 )
     803                 :            :         {
     804                 :          1 :             m_bEOF = true;
     805                 :          1 :             break;
     806                 :            :         }
     807         [ +  + ]:          1 :         if( strncmp(pszLine, "rec;", 4) != 0 )
     808                 :          1 :             continue;
     809                 :            : 
     810                 :            :         char** papszTokens = CSLTokenizeString2(pszLine+4,";",
     811                 :          1 :                 CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES| CSLT_STRIPENDSPACES);
     812         [ +  - ]:          1 :         poFeature = new OGRFeature(m_poFeatureDefn);
     813                 :          1 :         poFeature->SetFID( m_nFID ++ );
     814 [ +  + ][ +  - ]:          1 :         for(int i=0; i < m_poFeatureDefn->GetFieldCount() &&
                 [ +  + ]
     815                 :          1 :                      papszTokens[i] != NULL ;i++)
     816                 :            :         {
     817 [ +  - ][ +  + ]:          1 :             if( papszTokens[i][0] && !EQUAL(papszTokens[i], "NULL") )
     818                 :            :             {
     819                 :          1 :                 size_t nLen = strlen(papszTokens[i]);
     820                 :          1 :                 CPLString osToken;
     821 [ +  + ][ +  + ]:          1 :                 if( nLen >= 2 &&
                 [ +  - ]
     822                 :          1 :                     papszTokens[i][0] == '"' && papszTokens[i][nLen-1] == '"' )
     823                 :            :                 {
     824                 :          1 :                     papszTokens[i][nLen-1] = 0;
     825 [ +  - ][ +  - ]:          1 :                     osToken = OGRVDVUnescapeString(papszTokens[i]+1);
                 [ +  - ]
     826                 :            :                 }
     827                 :            :                 else
     828 [ +  - ][ +  - ]:          1 :                     osToken = papszTokens[i];
                 [ +  - ]
     829                 :            :                 // Strip trailing spaces
     830 [ +  - ][ +  - ]:          1 :                 while( !osToken.empty() && osToken.back() == ' ' )
         [ +  - ][ -  + ]
                 [ -  + ]
     831 [ #  # ][ #  # ]:          0 :                     osToken.resize(osToken.size()-1);
     832 [ +  - ][ +  - ]:          1 :                 OGRFieldType eFieldType = m_poFeatureDefn->GetFieldDefn(i)->GetType();
     833 [ +  + ][ +  + ]:          1 :                 if( m_bRecodeFromLatin1 && eFieldType == OFTString )
     834                 :            :                 {
     835                 :            :                     char* pszRecoded = CPLRecode(osToken,
     836 [ +  - ][ +  - ]:          1 :                                         CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
     837         [ +  - ]:          1 :                     poFeature->SetField(i, pszRecoded);
     838         [ +  - ]:          1 :                     CPLFree(pszRecoded);
     839                 :            :                 }
     840 [ +  + ][ +  - ]:          1 :                 else if( eFieldType == OFTString || !EQUAL(osToken, "NULL") )
         [ +  - ][ +  - ]
     841                 :            :                 {
     842 [ +  - ][ +  - ]:          1 :                     poFeature->SetField(i, osToken);
     843                 :          1 :                 }
     844                 :            :             }
     845                 :            :         }
     846                 :          1 :         CSLDestroy(papszTokens);
     847                 :            : 
     848 [ +  + ][ +  - ]:          1 :         if( m_iLongitudeVDV452 >= 0 && m_iLatitudeVDV452 >= 0 )
     849                 :            :         {
     850                 :          1 :             int nLongDegMinMS = poFeature->GetFieldAsInteger(m_iLongitudeVDV452);
     851                 :          1 :             int nLongSign = 1;
     852         [ +  - ]:          1 :             if( nLongDegMinMS < 0 )
     853                 :            :             {
     854                 :          1 :                 nLongSign = -1;
     855                 :          1 :                 nLongDegMinMS = -nLongDegMinMS;
     856                 :            :             }
     857                 :          1 :             const int nLongDeg = nLongDegMinMS / (100 * 100000);
     858                 :          1 :             const int nLongMin = (nLongDegMinMS / 100000) % 100;
     859                 :          1 :             const int nLongMS = nLongDegMinMS % 100000;
     860                 :            :             const double dfLong =
     861                 :          1 :                 (nLongDeg + nLongMin / 60.0 + nLongMS / (3600.0 * 1000.0)) * nLongSign;
     862                 :            : 
     863                 :          1 :             int nLatDegMinMS = poFeature->GetFieldAsInteger(m_iLatitudeVDV452);
     864                 :          1 :             int nLatSign = 1;
     865         [ +  - ]:          1 :             if( nLatDegMinMS < 0 )
     866                 :            :             {
     867                 :          1 :                 nLatSign = -1;
     868                 :          1 :                 nLatDegMinMS = -nLatDegMinMS;
     869                 :            :             }
     870                 :          1 :             const int nLatDeg = nLatDegMinMS / (100 * 100000);
     871                 :          1 :             const int nLatMin = (nLatDegMinMS / 100000) % 100;
     872                 :          1 :             const int nLatMS = nLatDegMinMS % 100000;
     873                 :            :             const double dfLat =
     874                 :          1 :                 (nLatDeg + nLatMin / 60.0 + nLatMS / (3600.0 * 1000.0)) * nLatSign;
     875                 :            : 
     876 [ -  + ][ #  # ]:          1 :             if( dfLong != 0.0 || dfLat != 0.0 )
     877                 :            :             {
     878         [ +  - ]:          1 :                 OGRPoint* poPoint = new OGRPoint(dfLong, dfLat);
     879                 :            :                 poPoint->assignSpatialReference(
     880                 :          1 :                     m_poFeatureDefn->GetGeomFieldDefn(0)->GetSpatialRef());
     881                 :          1 :                 poFeature->SetGeometryDirectly( poPoint );
     882                 :            :             }
     883                 :            :         }
     884                 :            : 
     885   [ -  +  #  # ]:          1 :         if( (m_poFilterGeom == NULL
           [ +  +  +  + ]
                 [ +  + ]
     886                 :          0 :             || FilterGeometry( poFeature->GetGeomFieldRef(m_iGeomFieldFilter) ) )
     887                 :            :             && (m_poAttrQuery == NULL
     888                 :          1 :                 || m_poAttrQuery->Evaluate( poFeature )) )
     889                 :            :         {
     890                 :          1 :             break;
     891                 :            :         }
     892         [ +  - ]:          1 :         delete poFeature;
     893                 :          1 :         poFeature = NULL;
     894                 :            :     }
     895                 :          1 :     m_nCurOffset = VSIFTellL(m_fpL);
     896                 :          1 :     return poFeature;
     897                 :            : }
     898                 :            : 
     899                 :            : /************************************************************************/
     900                 :            : /*                          TestCapability()                            */
     901                 :            : /************************************************************************/
     902                 :            : 
     903                 :          1 : int OGRVDVLayer::TestCapability(const char* pszCap)
     904                 :            : {
     905 [ -  + ][ #  # ]:          1 :     if( EQUAL(pszCap, OLCFastFeatureCount) &&  m_nTotalFeatureCount > 0 &&
         [ #  # ][ #  # ]
     906                 :            :         m_poFilterGeom == NULL && m_poAttrQuery == NULL )
     907                 :            :     {
     908                 :          0 :         return TRUE;
     909                 :            :     }
     910         [ +  + ]:          1 :     if( EQUAL(pszCap, OLCStringsAsUTF8) )
     911                 :            :     {
     912                 :          1 :         return m_bRecodeFromLatin1;
     913                 :            :     }
     914                 :          1 :     return FALSE;
     915                 :            : }
     916                 :            : 
     917                 :            : /************************************************************************/
     918                 :            : /*                          GetFeatureCount()                           */
     919                 :            : /************************************************************************/
     920                 :            : 
     921                 :          1 : GIntBig OGRVDVLayer::GetFeatureCount(int bForce)
     922                 :            : {
     923 [ +  + ][ +  - ]:          1 :     if( m_nTotalFeatureCount == 0 ||
                 [ +  + ]
     924                 :            :         m_poFilterGeom != NULL || m_poAttrQuery != NULL )
     925                 :            :     {
     926                 :          1 :         return OGRLayer::GetFeatureCount(bForce);
     927                 :            :     }
     928                 :          1 :     return m_nTotalFeatureCount;
     929                 :            : }
     930                 :            : 
     931                 :            : /************************************************************************/
     932                 :            : /*                              Identify()                              */
     933                 :            : /************************************************************************/
     934                 :            : 
     935                 :          1 : static int OGRVDVDriverIdentify( GDALOpenInfo* poOpenInfo )
     936                 :            : 
     937                 :            : {
     938         [ +  + ]:          1 :     if( poOpenInfo->bIsDirectory )
     939                 :          1 :         return -1; /* perhaps... */
     940                 :            :     return (poOpenInfo->nHeaderBytes > 0 &&
     941                 :          1 :             (strstr((const char*)poOpenInfo->pabyHeader, "\ntbl;") != NULL ||
     942                 :          1 :              strncmp((const char*)poOpenInfo->pabyHeader, "tbl;", 4) == 0) &&
     943                 :          1 :             strstr((const char*)poOpenInfo->pabyHeader, "\natr;") != NULL &&
     944   [ +  +  +  + ]:          1 :             strstr((const char*)poOpenInfo->pabyHeader, "\nfrm;") != NULL);
           [ +  +  +  - ]
                 [ +  - ]
     945                 :            : }
     946                 :            : 
     947                 :            : /************************************************************************/
     948                 :            : /*                                Open()                                */
     949                 :            : /************************************************************************/
     950                 :            : 
     951                 :          1 : GDALDataset *OGRVDVDataSource::Open( GDALOpenInfo* poOpenInfo )
     952                 :            : 
     953                 :            : {
     954         [ +  + ]:          1 :     if( !OGRVDVDriverIdentify(poOpenInfo) )
     955                 :            :     {
     956                 :          1 :         return NULL;
     957                 :            :     }
     958         [ +  + ]:          1 :     if( poOpenInfo->bIsDirectory )
     959                 :            :     {
     960                 :          1 :         char** papszFiles = VSIReadDir(poOpenInfo->pszFilename);
     961                 :            : 
     962                 :            :         // Identify the extension with the most occurrences
     963                 :          1 :         std::map<CPLString, int> oMapOtherExtensions;
     964 [ +  - ][ +  - ]:          1 :         CPLString osMajorityExtension, osMajorityFile;
     965                 :          1 :         int nFiles = 0;
     966 [ +  + ][ +  + ]:          1 :         for(char** papszIter = papszFiles; papszIter && *papszIter; ++papszIter)
                 [ +  + ]
     967                 :            :         {
     968 [ +  + ][ +  + ]:          1 :             if( EQUAL(*papszIter, ".") || EQUAL(*papszIter, "..") )
     969                 :          1 :                 continue;
     970                 :          1 :             nFiles ++;
     971 [ +  - ][ +  - ]:          1 :             CPLString osExtension(CPLGetExtension(*papszIter));
     972         [ +  - ]:          1 :             int nCount = ++oMapOtherExtensions[osExtension];
     973 [ +  - ][ +  + ]:          1 :             if( osMajorityExtension == "" ||
         [ +  + ][ +  + ]
     974         [ +  - ]:          1 :                 nCount > oMapOtherExtensions[osMajorityExtension] )
     975                 :            :             {
     976         [ +  - ]:          1 :                 osMajorityExtension = osExtension;
     977 [ +  - ][ +  - ]:          1 :                 osMajorityFile = *papszIter;
                 [ +  - ]
     978                 :            :             }
     979         [ +  - ]:          1 :         }
     980                 :            : 
     981                 :            :         // Check it is at least 50% of the files in the directory
     982 [ +  - ][ +  + ]:          1 :         if( osMajorityExtension == "" ||
         [ +  + ][ +  + ]
     983         [ +  - ]:          1 :             2 * oMapOtherExtensions[osMajorityExtension] < nFiles )
     984                 :            :         {
     985         [ +  - ]:          1 :             CSLDestroy(papszFiles);
     986                 :          1 :             return NULL;
     987                 :            :         }
     988                 :            : 
     989                 :            :         // And check that one of those files is a VDV one if it isn't .x10
     990 [ +  - ][ +  + ]:          1 :         if( osMajorityExtension != "x10" )
     991                 :            :         {
     992                 :            :             GDALOpenInfo oOpenInfo( CPLFormFilename(poOpenInfo->pszFilename,
     993                 :            :                                                     osMajorityFile,
     994 [ +  - ][ +  - ]:          1 :                                                     NULL), GA_ReadOnly );
                 [ +  - ]
     995         [ +  + ]:          1 :             if( OGRVDVDriverIdentify(&oOpenInfo) != TRUE )
     996                 :            :             {
     997         [ +  - ]:          1 :                 CSLDestroy(papszFiles);
     998                 :          1 :                 return NULL;
     999 [ +  - ][ +  + ]:          1 :             }
    1000                 :            :         }
    1001                 :            : 
    1002                 :            :         OGRVDVDataSource* poDS = new OGRVDVDataSource(poOpenInfo->pszFilename,
    1003                 :            :                                                       NULL, /* fp */
    1004                 :            :                                                       poOpenInfo->eAccess == GA_Update,
    1005                 :            :                                                       false, /* single file */
    1006 [ +  - ][ +  - ]:          1 :                                                       false /* new */);
    1007                 :            : 
    1008                 :            :         // Instantiate the layers.
    1009 [ +  - ][ +  + ]:          1 :         for(char** papszIter = papszFiles; papszIter && *papszIter; ++papszIter)
                 [ +  + ]
    1010                 :            :         {
    1011 [ +  - ][ +  - ]:          1 :             if( !EQUAL(CPLGetExtension(*papszIter), osMajorityExtension) )
                 [ +  + ]
    1012                 :          1 :                 continue;
    1013                 :            :             VSILFILE* fp = VSIFOpenL( CPLFormFilename(poOpenInfo->pszFilename,
    1014                 :            :                                                       *papszIter,
    1015 [ +  - ][ +  - ]:          1 :                                                       NULL), "rb");
    1016         [ -  + ]:          1 :             if( fp == NULL )
    1017                 :          0 :                 continue;
    1018                 :            :             poDS->m_papoLayers = static_cast<OGRLayer**>(CPLRealloc(
    1019         [ +  - ]:          1 :                 poDS->m_papoLayers, sizeof(OGRLayer*) * (poDS->m_nLayerCount + 1) ));
    1020                 :          1 :             poDS->m_papoLayers[poDS->m_nLayerCount] = new OGRVDVLayer(
    1021                 :            :                                                             CPLGetBasename(*papszIter),
    1022                 :            :                                                             fp,
    1023                 :            :                                                             true,
    1024                 :            :                                                             false,
    1025 [ +  - ][ +  - ]:          1 :                                                             0 );
         [ +  - ][ +  - ]
                 [ +  - ]
    1026                 :          1 :             poDS->m_nLayerCount ++;
    1027                 :            :         }
    1028         [ +  - ]:          1 :         CSLDestroy(papszFiles);
    1029                 :            : 
    1030         [ -  + ]:          1 :         if( poDS->m_nLayerCount == 0 )
    1031                 :            :         {
    1032 [ #  # ][ #  # ]:          0 :             delete poDS;
    1033                 :          0 :             poDS = NULL;
    1034                 :            :         }
    1035 [ +  - ][ +  - ]:          1 :         return poDS;
    1036                 :            :     }
    1037                 :            : 
    1038                 :          1 :     VSILFILE* fpL = poOpenInfo->fpL;
    1039                 :          1 :     poOpenInfo->fpL = NULL;
    1040                 :          1 :     const char* pszHeader = (const char*)poOpenInfo->pabyHeader;
    1041   [ +  +  +  -  :          1 :     if( strstr(pszHeader, "tbl;Node\r\natr;NODE_ID;") != NULL ||
          +  -  +  -  +  
                -  -  + ]
    1042                 :          1 :         strstr(pszHeader, "tbl;Node\natr;NODE_ID;") != NULL ||
    1043                 :          1 :         strstr(pszHeader, "tbl;Link\r\natr;LINK_ID;") != NULL ||
    1044                 :          1 :         strstr(pszHeader, "tbl;Link\natr;LINK_ID;") != NULL ||
    1045                 :          1 :         strstr(pszHeader, "tbl;LinkCoordinate\r\natr;LINK_ID;") != NULL ||
    1046                 :          1 :         strstr(pszHeader, "tbl;LinkCoordinate\natr;LINK_ID;") != NULL )
    1047                 :            :     {
    1048         [ +  - ]:          1 :         return new OGRIDFDataSource(fpL);
    1049                 :            :     }
    1050                 :            :     else
    1051                 :            :     {
    1052                 :            :         return new OGRVDVDataSource(poOpenInfo->pszFilename,
    1053                 :            :                                     fpL,
    1054                 :            :                                     poOpenInfo->eAccess == GA_Update,
    1055                 :            :                                     true, /* single file */
    1056         [ +  - ]:          1 :                                     false /* new */);
    1057                 :            :     }
    1058                 :            : }
    1059                 :            : 
    1060                 :            : /************************************************************************/
    1061                 :            : /*                         OGRVDVWriterLayer                            */
    1062                 :            : /************************************************************************/
    1063                 :            : 
    1064                 :          1 : OGRVDVWriterLayer::OGRVDVWriterLayer( OGRVDVDataSource *poDS,
    1065                 :            :                                       const char* pszName,
    1066                 :            :                                       VSILFILE* fpL,
    1067                 :            :                                       bool bOwnFP,
    1068                 :            :                                       OGRVDV452Table* poVDV452Table,
    1069                 :            :                                       const CPLString& osVDV452Lang,
    1070                 :            :                                       bool bProfileStrict):
    1071                 :            :     m_poDS(poDS),
    1072         [ +  - ]:          1 :     m_poFeatureDefn(new OGRFeatureDefn(pszName)),
    1073                 :            :     m_bWritePossible(true),
    1074                 :            :     m_fpL(fpL),
    1075                 :            :     m_bOwnFP(bOwnFP),
    1076                 :            :     m_nFeatureCount(-1),
    1077                 :            :     m_poVDV452Table(poVDV452Table),
    1078                 :            :     m_osVDV452Lang(osVDV452Lang),
    1079                 :            :     m_bProfileStrict(bProfileStrict),
    1080                 :            :     m_iLongitudeVDV452(-1),
    1081 [ +  - ][ +  - ]:          1 :     m_iLatitudeVDV452(-1)
    1082                 :            : {
    1083         [ +  - ]:          1 :     m_poFeatureDefn->SetGeomType(wkbNone);
    1084         [ +  - ]:          1 :     m_poFeatureDefn->Reference();
    1085         [ +  - ]:          1 :     SetDescription(pszName);
    1086                 :          1 : }
    1087                 :            : 
    1088                 :            : /************************************************************************/
    1089                 :            : /*                        ~OGRVDVWriterLayer                            */
    1090                 :            : /************************************************************************/
    1091                 :            : 
    1092         [ +  - ]:          1 : OGRVDVWriterLayer::~OGRVDVWriterLayer()
    1093                 :            : {
    1094         [ +  - ]:          1 :     StopAsCurrentLayer();
    1095                 :            : 
    1096         [ +  - ]:          1 :     m_poFeatureDefn->Release();
    1097         [ +  + ]:          1 :     if( m_bOwnFP )
    1098                 :            :     {
    1099         [ +  - ]:          1 :         VSIFPrintfL( m_fpL, "eof; %d\n", 1 );
    1100         [ +  - ]:          1 :         VSIFCloseL(m_fpL);
    1101                 :            :     }
    1102         [ -  + ]:          1 : }
    1103                 :            : 
    1104                 :            : /************************************************************************/
    1105                 :            : /*                          ResetReading()                              */
    1106                 :            : /************************************************************************/
    1107                 :            : 
    1108                 :          1 : void OGRVDVWriterLayer::ResetReading()
    1109                 :            : {
    1110                 :          1 : }
    1111                 :            : 
    1112                 :            : /************************************************************************/
    1113                 :            : /*                          GetNextFeature()                            */
    1114                 :            : /************************************************************************/
    1115                 :            : 
    1116                 :          1 : OGRFeature* OGRVDVWriterLayer::GetNextFeature()
    1117                 :            : {
    1118                 :            :     CPLError(CE_Failure, CPLE_NotSupported,
    1119                 :          1 :              "GetNextFeature() not supported on write-only layer");
    1120                 :          1 :     return NULL;
    1121                 :            : }
    1122                 :            : 
    1123                 :            : /************************************************************************/
    1124                 :            : /*                         OGRVDVEscapeString()                         */
    1125                 :            : /************************************************************************/
    1126                 :            : 
    1127                 :          1 : static CPLString OGRVDVEscapeString(const char* pszValue)
    1128                 :            : {
    1129                 :          1 :     CPLString osRet;
    1130         [ +  + ]:          1 :     for( ; *pszValue != '\0'; ++pszValue )
    1131                 :            :     {
    1132         [ +  + ]:          1 :         if( *pszValue == '"' )
    1133         [ +  - ]:          1 :             osRet += "\"\"";
    1134                 :            :         else
    1135         [ +  - ]:          1 :             osRet += *pszValue;
    1136                 :            :     }
    1137                 :          1 :     return osRet;
    1138                 :            : }
    1139                 :            : 
    1140                 :            : /************************************************************************/
    1141                 :            : /*                          WriteSchemaIfNeeded()                       */
    1142                 :            : /************************************************************************/
    1143                 :            : 
    1144                 :          1 : bool OGRVDVWriterLayer::WriteSchemaIfNeeded()
    1145                 :            : {
    1146         [ +  + ]:          1 :     if( m_nFeatureCount < 0 )
    1147                 :            :     {
    1148                 :          1 :         m_nFeatureCount = 0;
    1149                 :            : 
    1150                 :          1 :         bool bOK = VSIFPrintfL(m_fpL, "tbl; %s\n", m_poFeatureDefn->GetName()) > 0;
    1151                 :          1 :         bOK &= VSIFPrintfL(m_fpL, "atr;") > 0;
    1152         [ +  + ]:          1 :         for( int i=0; i < m_poFeatureDefn->GetFieldCount(); i++ )
    1153                 :            :         {
    1154         [ +  + ]:          1 :             if( i > 0)
    1155                 :          1 :                 bOK &= VSIFPrintfL(m_fpL, ";") > 0;
    1156                 :            :             bOK &= VSIFPrintfL(m_fpL, " %s",
    1157                 :          1 :                                m_poFeatureDefn->GetFieldDefn(i)->GetNameRef()) > 0;
    1158                 :            :         }
    1159                 :          1 :         bOK &= VSIFPrintfL(m_fpL, "\n") > 0;
    1160                 :          1 :         bOK &= VSIFPrintfL(m_fpL, "frm;") > 0;
    1161         [ +  + ]:          1 :         for( int i=0; i < m_poFeatureDefn->GetFieldCount(); i++ )
    1162                 :            :         {
    1163         [ +  + ]:          1 :             if( i > 0)
    1164                 :          1 :                 bOK &= VSIFPrintfL(m_fpL, ";") > 0;
    1165                 :          1 :             bOK &= VSIFPrintfL(m_fpL, " ") > 0;
    1166                 :          1 :             int nWidth = m_poFeatureDefn->GetFieldDefn(i)->GetWidth();
    1167                 :          1 :             const OGRFieldType eType = m_poFeatureDefn->GetFieldDefn(i)->GetType();
    1168         [ +  + ]:          1 :             switch( eType )
    1169                 :            :             {
    1170                 :            :                 case OFTInteger:
    1171                 :            :                 case OFTInteger64:
    1172         [ +  + ]:          1 :                     if( m_poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean )
    1173                 :            :                     {
    1174                 :          1 :                         bOK &= VSIFPrintfL(m_fpL, "boolean") > 0;
    1175                 :            :                     }
    1176                 :            :                     else
    1177                 :            :                     {
    1178         [ +  + ]:          1 :                         if( nWidth == 0 )
    1179                 :            :                         {
    1180         [ +  + ]:          1 :                             if( eType == OFTInteger )
    1181                 :          1 :                                 nWidth = 11;
    1182                 :            :                             else
    1183                 :          1 :                                 nWidth = 20;
    1184                 :            :                         }
    1185                 :          1 :                         nWidth --; /* VDV 451 is without sign */
    1186                 :          1 :                         bOK &= VSIFPrintfL(m_fpL, "num[%d.0]", nWidth) > 0;
    1187                 :            :                     }
    1188                 :          1 :                     break;
    1189                 :            : 
    1190                 :            :                 default:
    1191         [ +  + ]:          1 :                     if( nWidth == 0 )
    1192                 :            :                     {
    1193                 :          1 :                         nWidth = 80;
    1194                 :            :                     }
    1195                 :          1 :                     bOK &= VSIFPrintfL(m_fpL, "char[%d]", nWidth) > 0;
    1196                 :          1 :                     break;
    1197                 :            :             }
    1198                 :            :         }
    1199                 :          1 :         bOK &= VSIFPrintfL(m_fpL, "\n") > 0;
    1200                 :            : 
    1201         [ -  + ]:          1 :         if( !bOK )
    1202                 :          0 :             return false;
    1203                 :            :     }
    1204                 :            : 
    1205                 :          1 :     return true;
    1206                 :            : }
    1207                 :            : 
    1208                 :            : /************************************************************************/
    1209                 :            : /*                         ICreateFeature()                             */
    1210                 :            : /************************************************************************/
    1211                 :            : 
    1212                 :          1 : OGRErr OGRVDVWriterLayer::ICreateFeature(OGRFeature* poFeature)
    1213                 :            : {
    1214         [ +  + ]:          1 :     if( !m_bWritePossible )
    1215                 :            :     {
    1216                 :            :         CPLError(CE_Failure, CPLE_NotSupported,
    1217                 :            :                  "Layer %s is no longer the active layer. "
    1218                 :            :                  "Writing in it is no longer possible",
    1219                 :          1 :                  m_poFeatureDefn->GetName());
    1220                 :          1 :         return OGRERR_FAILURE;
    1221                 :            :     }
    1222                 :          1 :     m_poDS->SetCurrentWriterLayer(this);
    1223                 :            : 
    1224                 :          1 :     WriteSchemaIfNeeded();
    1225                 :            : 
    1226                 :          1 :     bool bOK = VSIFPrintfL(m_fpL, "rec; ") > 0;
    1227         [ +  + ]:          1 :     for( int i=0; i < m_poFeatureDefn->GetFieldCount(); i++ )
    1228                 :            :     {
    1229         [ +  + ]:          1 :         if( i > 0)
    1230                 :          1 :             bOK &= VSIFPrintfL(m_fpL, "; ") > 0;
    1231         [ +  + ]:          1 :         if( poFeature->IsFieldSetAndNotNull(i) )
    1232                 :            :         {
    1233                 :          1 :             const OGRFieldType eType = m_poFeatureDefn->GetFieldDefn(i)->GetType();
    1234 [ +  + ][ +  + ]:          1 :             if( eType == OFTInteger || eType == OFTInteger64 )
    1235                 :            :             {
    1236                 :            :                 bOK &= VSIFPrintfL(m_fpL, CPL_FRMT_GIB,
    1237                 :          1 :                                    poFeature->GetFieldAsInteger64(i)) > 0;
    1238                 :            :             }
    1239                 :            :             else
    1240                 :            :             {
    1241                 :            :                 char* pszRecoded = CPLRecode(poFeature->GetFieldAsString(i),
    1242                 :          1 :                                               CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    1243                 :            :                 bOK &= VSIFPrintfL(m_fpL, "\"%s\"",
    1244 [ +  - ][ +  - ]:          1 :                                    OGRVDVEscapeString(pszRecoded).c_str()) > 0;
    1245                 :          1 :                 CPLFree(pszRecoded);
    1246                 :            :             }
    1247                 :            :         }
    1248   [ +  +  +  -  :          1 :         else if( i == m_iLongitudeVDV452 &&
           +  - ][ +  + ]
    1249                 :          1 :                  poFeature->GetGeometryRef() != NULL &&
    1250                 :          1 :                  poFeature->GetGeometryRef()->getGeometryType() == wkbPoint )
    1251                 :            :         {
    1252                 :          1 :             OGRPoint* poPoint = static_cast<OGRPoint*>(poFeature->GetGeometryRef());
    1253                 :          1 :             const double dfDeg = poPoint->getX();
    1254                 :          1 :             const double dfAbsDeg = fabs(dfDeg);
    1255                 :          1 :             const int nDeg = static_cast<int>(dfAbsDeg);
    1256                 :          1 :             const int nMin = static_cast<int>((dfAbsDeg - nDeg) * 60);
    1257                 :          1 :             const double dfSec = (dfAbsDeg - nDeg)*3600 - nMin * 60;
    1258                 :          1 :             const int nSec = static_cast<int>(dfSec);
    1259                 :          1 :             int nMS = static_cast<int>((dfSec - nSec) * 1000 + 0.5);
    1260         [ -  + ]:          1 :             if( nMS == 1000 ) nMS = 999;
    1261         [ +  - ]:          1 :             if( dfDeg < 0 )
    1262                 :          1 :                 bOK &= VSIFPrintfL(m_fpL, "-") > 0;
    1263                 :          1 :             bOK &= VSIFPrintfL(m_fpL, "%03d%02d%02d%03d", nDeg, nMin, nSec, nMS) > 0;
    1264                 :            :         }
    1265   [ +  +  +  -  :          1 :         else if( i == m_iLatitudeVDV452 &&
           +  - ][ +  + ]
    1266                 :          1 :                  poFeature->GetGeometryRef() != NULL &&
    1267                 :          1 :                  poFeature->GetGeometryRef()->getGeometryType() == wkbPoint )
    1268                 :            :         {
    1269                 :          1 :             OGRPoint* poPoint = static_cast<OGRPoint*>(poFeature->GetGeometryRef());
    1270                 :          1 :             const double dfDeg = poPoint->getY();
    1271                 :          1 :             const double dfAbsDeg = fabs(dfDeg);
    1272                 :          1 :             const int nDeg = static_cast<int>(dfAbsDeg);
    1273                 :          1 :             const int nMin = static_cast<int>((dfAbsDeg - nDeg) * 60);
    1274                 :          1 :             const double dfSec = (dfAbsDeg - nDeg)*3600 - nMin * 60;
    1275                 :          1 :             const int nSec = static_cast<int>(dfSec);
    1276                 :          1 :             int nMS = static_cast<int>((dfSec - nSec) * 1000 + 0.5);
    1277         [ -  + ]:          1 :             if( nMS == 1000 ) nMS = 999;
    1278         [ +  - ]:          1 :             if( dfDeg < 0 )
    1279                 :          1 :                 bOK &= VSIFPrintfL(m_fpL, "-") > 0;
    1280                 :          1 :             bOK &= VSIFPrintfL(m_fpL, "%02d%02d%02d%03d", nDeg, nMin, nSec, nMS) > 0;
    1281                 :            :         }
    1282                 :            :         else
    1283                 :            :         {
    1284                 :          1 :             bOK &= VSIFPrintfL(m_fpL, "NULL") > 0;
    1285                 :            :         }
    1286                 :            :     }
    1287                 :          1 :     bOK &= VSIFPrintfL(m_fpL, "\n") > 0;
    1288                 :            : 
    1289         [ -  + ]:          1 :     if( !bOK )
    1290                 :          0 :         return OGRERR_FAILURE;
    1291                 :            : 
    1292                 :          1 :     m_nFeatureCount ++;
    1293                 :          1 :     return OGRERR_NONE;
    1294                 :            : }
    1295                 :            : 
    1296                 :            : /************************************************************************/
    1297                 :            : /*                         GetFeatureCount()                            */
    1298                 :            : /************************************************************************/
    1299                 :            : 
    1300                 :          1 : GIntBig OGRVDVWriterLayer::GetFeatureCount( int )
    1301                 :            : {
    1302                 :          1 :     return m_nFeatureCount >= 0 ? m_nFeatureCount : 0;
    1303                 :            : }
    1304                 :            : 
    1305                 :            : /************************************************************************/
    1306                 :            : /*                          CreateField()                               */
    1307                 :            : /************************************************************************/
    1308                 :            : 
    1309                 :          1 : OGRErr OGRVDVWriterLayer::CreateField(OGRFieldDefn* poFieldDefn, int /* bApprox */)
    1310                 :            : {
    1311         [ +  + ]:          1 :     if( m_nFeatureCount >= 0 )
    1312                 :            :     {
    1313                 :            :         CPLError(CE_Failure, CPLE_NotSupported,
    1314                 :          1 :                  "Fields can no longer by added to layer %s",m_poFeatureDefn->GetName());
    1315                 :          1 :         return OGRERR_FAILURE;
    1316                 :            :     }
    1317                 :            : 
    1318         [ +  + ]:          1 :     if( m_poVDV452Table != NULL )
    1319                 :            :     {
    1320                 :          1 :         bool bFound = false;
    1321         [ +  + ]:          1 :         for(size_t i=0;i<m_poVDV452Table->aosFields.size();i++)
    1322                 :            :         {
    1323                 :          1 :             const char* pszFieldName = poFieldDefn->GetNameRef();
    1324   [ +  +  +  +  :          1 :             if( (m_osVDV452Lang == "en" &&
             +  +  +  + ]
                 [ +  + ]
    1325                 :          1 :                  EQUAL(m_poVDV452Table->aosFields[i].osEnglishName, pszFieldName)) ||
    1326                 :          1 :                 (m_osVDV452Lang == "de" &&
    1327                 :          1 :                  EQUAL(m_poVDV452Table->aosFields[i].osGermanName, pszFieldName)) )
    1328                 :            :             {
    1329                 :          1 :                 bFound = true;
    1330                 :          1 :                 break;
    1331                 :            :             }
    1332                 :            :         }
    1333         [ +  + ]:          1 :         if( !bFound )
    1334                 :            :         {
    1335                 :            :             CPLError(m_bProfileStrict ? CE_Failure : CE_Warning, CPLE_AppDefined,
    1336                 :            :                      "Field %s is not an allowed field for table %s",
    1337         [ +  + ]:          1 :                      poFieldDefn->GetNameRef(), m_poFeatureDefn->GetName());
    1338         [ +  + ]:          1 :             if( m_bProfileStrict )
    1339                 :          1 :                 return OGRERR_FAILURE;
    1340                 :            :         }
    1341   [ +  +  +  - ]:          1 :         if( EQUAL(m_poFeatureDefn->GetName(), "STOP") ||
                 [ +  - ]
    1342                 :          1 :             EQUAL(m_poFeatureDefn->GetName(), "REC_ORT") )
    1343                 :            :         {
    1344   [ +  +  +  + ]:          1 :             if( EQUAL(poFieldDefn->GetNameRef(), "POINT_LONGITUDE") ||
                 [ +  + ]
    1345                 :          1 :                 EQUAL(poFieldDefn->GetNameRef(), "ORT_POS_LAENGE") )
    1346                 :            :             {
    1347                 :          1 :                 m_iLongitudeVDV452 = m_poFeatureDefn->GetFieldCount();
    1348                 :            :             }
    1349   [ +  +  +  + ]:          1 :             else if( EQUAL(poFieldDefn->GetNameRef(), "POINT_LATITUDE") ||
                 [ +  + ]
    1350                 :          1 :                 EQUAL(poFieldDefn->GetNameRef(), "ORT_POS_BREITE") )
    1351                 :            :             {
    1352                 :          1 :                 m_iLatitudeVDV452 = m_poFeatureDefn->GetFieldCount();
    1353                 :            :             }
    1354                 :            :         }
    1355                 :            :     }
    1356                 :            : 
    1357                 :          1 :     m_poFeatureDefn->AddFieldDefn(poFieldDefn);
    1358                 :          1 :     return OGRERR_NONE;
    1359                 :            : }
    1360                 :            : 
    1361                 :            : /************************************************************************/
    1362                 :            : /*                         TestCapability()                             */
    1363                 :            : /************************************************************************/
    1364                 :            : 
    1365                 :          1 : int OGRVDVWriterLayer::TestCapability(const char* pszCap)
    1366                 :            : {
    1367         [ +  + ]:          1 :     if( EQUAL(pszCap, OLCSequentialWrite) )
    1368                 :          1 :         return m_bWritePossible;
    1369         [ +  + ]:          1 :     if( EQUAL(pszCap, OLCCreateField) )
    1370                 :          1 :         return m_nFeatureCount < 0;
    1371                 :          1 :     return FALSE;
    1372                 :            : }
    1373                 :            : 
    1374                 :            : /************************************************************************/
    1375                 :            : /*                         StopAsCurrentLayer()                         */
    1376                 :            : /************************************************************************/
    1377                 :            : 
    1378                 :          1 : void OGRVDVWriterLayer::StopAsCurrentLayer()
    1379                 :            : {
    1380         [ +  + ]:          1 :     if( m_bWritePossible )
    1381                 :            :     {
    1382                 :          1 :         m_bWritePossible = false;
    1383         [ +  - ]:          1 :         if( m_fpL != NULL )
    1384                 :            :         {
    1385                 :          1 :             WriteSchemaIfNeeded();
    1386                 :          1 :             VSIFPrintfL(m_fpL, "end; " CPL_FRMT_GIB "\n", m_nFeatureCount);
    1387                 :            :         }
    1388                 :            :     }
    1389                 :          1 : }
    1390                 :            : 
    1391                 :            : /************************************************************************/
    1392                 :            : /*                         OGRVDVWriteHeader()                          */
    1393                 :            : /************************************************************************/
    1394                 :            : 
    1395                 :          1 : static bool OGRVDVWriteHeader(VSILFILE* fpL, char** papszOptions)
    1396                 :            : {
    1397                 :          1 :     bool bRet = true;
    1398                 :            :     const bool bStandardHeader =
    1399                 :          1 :             CPLFetchBool(papszOptions, "STANDARD_HEADER", true);
    1400                 :            : 
    1401                 :            :     struct tm tm;
    1402                 :          1 :     CPLUnixTimeToYMDHMS(time(NULL), &tm);
    1403                 :            :     const char* pszSrc = CSLFetchNameValueDef(papszOptions, "HEADER_SRC",
    1404         [ +  - ]:          1 :         (bStandardHeader ) ? "UNKNOWN" : NULL);
    1405                 :            :     const char* pszSrcDate = CSLFetchNameValueDef(papszOptions, "HEADER_SRC_DATE",
    1406         [ +  - ]:          1 :         (pszSrc) ? CPLSPrintf("%02d.%02d.%04d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900) : NULL);
    1407                 :            :     const char* pszSrcTime = CSLFetchNameValueDef(papszOptions, "HEADER_SRC_TIME",
    1408         [ +  - ]:          1 :         (pszSrc) ? CPLSPrintf("%02d.%02d.%02d", tm.tm_hour, tm.tm_min, tm.tm_sec) : NULL);
    1409                 :            : 
    1410 [ +  - ][ +  - ]:          1 :     if( pszSrc && pszSrcDate && pszSrcTime )
                 [ +  - ]
    1411                 :            :     {
    1412                 :          1 :         bRet &= VSIFPrintfL(fpL, "mod; DD.MM.YYYY; HH:MM:SS; free\n") > 0;
    1413                 :            :         bRet &= VSIFPrintfL(fpL, "src; \"%s\"; \"%s\"; \"%s\"\n",
    1414                 :            :                             OGRVDVEscapeString(pszSrc).c_str(),
    1415                 :            :                             OGRVDVEscapeString(pszSrcDate).c_str(),
    1416 [ +  - ][ +  - ]:          1 :                             OGRVDVEscapeString(pszSrcTime).c_str()) > 0;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
    1417                 :            :     }
    1418                 :            : 
    1419         [ +  - ]:          1 :     if( bStandardHeader)
    1420                 :            :     {
    1421                 :          1 :         const char* pszChs = CSLFetchNameValueDef(papszOptions, "HEADER_CHS", "ISO8859-1");
    1422                 :          1 :         const char* pszVer = CSLFetchNameValueDef(papszOptions, "HEADER_VER", "1.4");
    1423                 :          1 :         const char* pszIfv = CSLFetchNameValueDef(papszOptions, "HEADER_IFV", "1.4");
    1424                 :          1 :         const char* pszDve = CSLFetchNameValueDef(papszOptions, "HEADER_DVE", "1.4");
    1425                 :          1 :         const char* pszFft = CSLFetchNameValueDef(papszOptions, "HEADER_FFT", "");
    1426                 :            : 
    1427 [ +  - ][ +  - ]:          1 :         bRet &= VSIFPrintfL(fpL, "chs; \"%s\"\n", OGRVDVEscapeString(pszChs).c_str()) > 0;
    1428 [ +  - ][ +  - ]:          1 :         bRet &= VSIFPrintfL(fpL, "ver; \"%s\"\n", OGRVDVEscapeString(pszVer).c_str()) > 0;
    1429 [ +  - ][ +  - ]:          1 :         bRet &= VSIFPrintfL(fpL, "ifv; \"%s\"\n", OGRVDVEscapeString(pszIfv).c_str()) > 0;
    1430 [ +  - ][ +  - ]:          1 :         bRet &= VSIFPrintfL(fpL, "dve; \"%s\"\n", OGRVDVEscapeString(pszDve).c_str()) > 0;
    1431 [ +  - ][ +  - ]:          1 :         bRet &= VSIFPrintfL(fpL, "fft; \"%s\"\n", OGRVDVEscapeString(pszFft).c_str()) > 0;
    1432                 :            :     }
    1433                 :            : 
    1434 [ +  + ][ +  + ]:          1 :     for(char** papszIter = papszOptions;
                 [ +  + ]
    1435                 :            :                papszIter != NULL && *papszIter != NULL;
    1436                 :            :                papszIter++)
    1437                 :            :     {
    1438 [ +  + ][ +  + ]:          1 :         if( STARTS_WITH_CI(*papszIter, "HEADER_") &&
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
    1439                 :          1 :             !STARTS_WITH_CI(*papszIter, "HEADER_SRC") &&
    1440                 :          1 :             (!bStandardHeader ||
    1441                 :          1 :              (!EQUAL(*papszIter, "HEADER_CHS") &&
    1442                 :          1 :               !EQUAL(*papszIter, "HEADER_VER") &&
    1443                 :          1 :               !EQUAL(*papszIter, "HEADER_IFV") &&
    1444                 :          1 :               !EQUAL(*papszIter, "HEADER_DVE") &&
    1445                 :          1 :               !EQUAL(*papszIter, "HEADER_FFT"))) )
    1446                 :            :         {
    1447                 :          1 :             char* pszKey = NULL;
    1448                 :          1 :             const char* pszValue = CPLParseNameValue(*papszIter, &pszKey);
    1449 [ +  - ][ +  - ]:          1 :             if( pszKey && strlen(pszKey) > strlen("HEADER_") && pszValue )
                 [ +  - ]
    1450                 :            :             {
    1451                 :            :                 bRet &= VSIFPrintfL(fpL, "%s; \"%s\"\n",
    1452                 :            :                                     pszKey + strlen("HEADER_"),
    1453 [ +  - ][ +  - ]:          1 :                                     OGRVDVEscapeString(pszValue).c_str()) > 0;
    1454                 :            :             }
    1455                 :          1 :             CPLFree(pszKey);
    1456                 :            :         }
    1457                 :            :     }
    1458                 :            : 
    1459                 :          1 :     return bRet;
    1460                 :            : }
    1461                 :            : 
    1462                 :            : /************************************************************************/
    1463                 :            : /*                      OGRVDVLoadVDV452Tables()                        */
    1464                 :            : /************************************************************************/
    1465                 :            : 
    1466                 :          1 : static bool OGRVDVLoadVDV452Tables(OGRVDV452Tables& oTables)
    1467                 :            : {
    1468                 :          1 :     const char* pszXMLDescFilename = CPLFindFile("gdal", "vdv452.xml");
    1469         [ -  + ]:          1 :     if (pszXMLDescFilename == NULL)
    1470                 :            :     {
    1471                 :          0 :         CPLDebug("VDV", "Cannot find XML file : %s", "vdv452.xml");
    1472                 :          0 :         return false;
    1473                 :            :     }
    1474                 :            : 
    1475                 :          1 :     CPLXMLNode* psRoot = CPLParseXMLFile(pszXMLDescFilename);
    1476         [ -  + ]:          1 :     if( psRoot == NULL)
    1477                 :            :     {
    1478                 :          0 :         return false;
    1479                 :            :     }
    1480                 :          1 :     CPLXMLNode* psTables = CPLGetXMLNode(psRoot, "=Layers");
    1481         [ +  - ]:          1 :     if( psTables != NULL )
    1482                 :            :     {
    1483         [ +  + ]:          1 :         for(CPLXMLNode* psTable = psTables->psChild;
    1484                 :            :                         psTable != NULL; psTable = psTable->psNext )
    1485                 :            :         {
    1486 [ +  - ][ -  + ]:          1 :             if( psTable->eType != CXT_Element || strcmp(psTable->pszValue, "Layer") != 0 )
    1487                 :          0 :                 continue;
    1488         [ +  - ]:          1 :             OGRVDV452Table* poTable = new OGRVDV452Table();
    1489         [ +  - ]:          1 :             poTable->osEnglishName = CPLGetXMLValue(psTable, "name_en", "");
    1490         [ +  - ]:          1 :             poTable->osGermanName = CPLGetXMLValue(psTable, "name_de", "");
    1491                 :          1 :             oTables.aosTables.push_back(poTable);
    1492                 :          1 :             oTables.oMapEnglish[poTable->osEnglishName] = poTable;
    1493                 :          1 :             oTables.oMapGerman[poTable->osGermanName] = poTable;
    1494         [ +  + ]:          1 :             for(CPLXMLNode* psField = psTable->psChild;
    1495                 :            :                         psField != NULL; psField = psField->psNext )
    1496                 :            :             {
    1497 [ +  + ][ -  + ]:          1 :                 if( psField->eType != CXT_Element || strcmp(psField->pszValue, "Field") != 0 )
    1498                 :          1 :                     continue;
    1499                 :          1 :                 OGRVDV452Field oField;
    1500 [ +  - ][ +  - ]:          1 :                 oField.osEnglishName = CPLGetXMLValue(psField, "name_en", "");
         [ +  - ][ +  - ]
    1501 [ +  - ][ +  - ]:          1 :                 oField.osGermanName = CPLGetXMLValue(psField, "name_de", "");
         [ +  - ][ +  - ]
    1502 [ +  - ][ +  - ]:          1 :                 oField.osType = CPLGetXMLValue(psField, "type", "");
         [ +  - ][ +  - ]
    1503         [ +  - ]:          1 :                 oField.nWidth = atoi(CPLGetXMLValue(psField, "width", "0"));
    1504         [ +  - ]:          1 :                 poTable->aosFields.push_back(oField);
    1505                 :          1 :             }
    1506                 :            :         }
    1507                 :            :     }
    1508                 :            : 
    1509                 :          1 :     CPLDestroyXMLNode(psRoot);
    1510                 :          1 :     return true;
    1511                 :            : }
    1512                 :            : 
    1513                 :            : /************************************************************************/
    1514                 :            : /*                           ICreateLayer()                             */
    1515                 :            : /************************************************************************/
    1516                 :            : 
    1517                 :            : OGRLayer *
    1518                 :          1 : OGRVDVDataSource::ICreateLayer( const char *pszLayerName,
    1519                 :            :                                 OGRSpatialReference * /*poSpatialRef*/,
    1520                 :            :                                 OGRwkbGeometryType eGType,
    1521                 :            :                                 char ** papszOptions  )
    1522                 :            : {
    1523         [ -  + ]:          1 :     if( !m_bUpdate )
    1524                 :          0 :         return NULL;
    1525                 :            : 
    1526                 :          1 :     const char* pszProfile = CSLFetchNameValueDef(papszOptions, "PROFILE", "GENERIC");
    1527 [ +  + ][ +  + ]:          1 :     if( STARTS_WITH_CI(pszProfile, "VDV-452") && !m_bVDV452Loaded )
    1528                 :            :     {
    1529                 :          1 :         m_bVDV452Loaded = true;
    1530                 :          1 :         OGRVDVLoadVDV452Tables(m_oVDV452Tables);
    1531                 :            :     }
    1532                 :            :     const bool bProfileStrict =
    1533                 :          1 :         CPLFetchBool(papszOptions, "PROFILE_STRICT", false);
    1534                 :            :     const bool bCreateAllFields =
    1535                 :          1 :         CPLFetchBool(papszOptions, "CREATE_ALL_FIELDS", true);
    1536                 :            : 
    1537                 :          1 :     CPLString osUpperLayerName(pszLayerName);
    1538         [ +  - ]:          1 :     osUpperLayerName.toupper();
    1539                 :            : 
    1540                 :          1 :     OGRVDV452Table* poVDV452Table = NULL;
    1541         [ +  - ]:          1 :     CPLString osVDV452Lang;
    1542                 :          1 :     bool bOKTable = true;
    1543         [ +  + ]:          1 :     if( EQUAL(pszProfile, "VDV-452") )
    1544                 :            :     {
    1545 [ +  - ][ +  + ]:          1 :         if( m_oVDV452Tables.oMapEnglish.find(osUpperLayerName) !=
    1546 [ +  - ][ +  - ]:          1 :             m_oVDV452Tables.oMapEnglish.end() )
    1547                 :            :         {
    1548         [ +  - ]:          1 :             poVDV452Table = m_oVDV452Tables.oMapEnglish[osUpperLayerName];
    1549 [ +  - ][ +  - ]:          1 :             osVDV452Lang = "en";
                 [ +  - ]
    1550                 :            :         }
    1551 [ +  - ][ +  + ]:          1 :         else if( m_oVDV452Tables.oMapGerman.find(osUpperLayerName) !=
    1552 [ +  - ][ +  - ]:          1 :                  m_oVDV452Tables.oMapGerman.end() )
    1553                 :            :         {
    1554         [ +  - ]:          1 :             poVDV452Table = m_oVDV452Tables.oMapGerman[osUpperLayerName];
    1555 [ +  - ][ +  - ]:          1 :             osVDV452Lang = "de";
                 [ +  - ]
    1556                 :            :         }
    1557                 :            :         else
    1558                 :            :         {
    1559                 :          1 :             bOKTable = false;
    1560                 :            :         }
    1561                 :            :     }
    1562         [ +  + ]:          1 :     else if( EQUAL(pszProfile, "VDV-452-ENGLISH") )
    1563                 :            :     {
    1564 [ +  - ][ +  + ]:          1 :         if( m_oVDV452Tables.oMapEnglish.find(osUpperLayerName) !=
    1565 [ +  - ][ +  - ]:          1 :             m_oVDV452Tables.oMapEnglish.end() )
    1566                 :            :         {
    1567         [ +  - ]:          1 :             poVDV452Table = m_oVDV452Tables.oMapEnglish[osUpperLayerName];
    1568 [ +  - ][ +  - ]:          1 :             osVDV452Lang = "en";
                 [ +  - ]
    1569                 :            :         }
    1570                 :            :         else
    1571                 :            :         {
    1572                 :          1 :             bOKTable = false;
    1573                 :            :         }
    1574                 :            :     }
    1575         [ +  + ]:          1 :     else if( EQUAL(pszProfile, "VDV-452-GERMAN") )
    1576                 :            :     {
    1577 [ +  - ][ +  + ]:          1 :         if( m_oVDV452Tables.oMapGerman.find(osUpperLayerName) !=
    1578 [ +  - ][ +  - ]:          1 :             m_oVDV452Tables.oMapGerman.end() )
    1579                 :            :         {
    1580         [ +  - ]:          1 :             poVDV452Table = m_oVDV452Tables.oMapGerman[osUpperLayerName];
    1581 [ +  - ][ +  - ]:          1 :             osVDV452Lang = "de";
                 [ +  - ]
    1582                 :            :         }
    1583                 :            :         else
    1584                 :            :         {
    1585                 :          1 :             bOKTable = false;
    1586                 :            :         }
    1587                 :            :     }
    1588         [ +  + ]:          1 :     if( !bOKTable )
    1589                 :            :     {
    1590                 :            :         CPLError(bProfileStrict ? CE_Failure : CE_Warning,
    1591                 :            :                  CPLE_AppDefined, "%s is not a VDV-452 table",
    1592 [ +  + ][ +  - ]:          1 :                  pszLayerName);
    1593         [ +  + ]:          1 :         if( bProfileStrict )
    1594                 :          1 :             return NULL;
    1595                 :            :     }
    1596                 :            : 
    1597                 :          1 :     VSILFILE* fpL = NULL;
    1598         [ +  + ]:          1 :     if( m_bSingleFile )
    1599                 :            :     {
    1600                 :          1 :         fpL = m_fpL;
    1601 [ +  + ][ +  - ]:          1 :         if( !m_bNew && m_nLayerCount == 0 )
    1602                 :            :         {
    1603                 :            :             // Find last non-empty line in the file
    1604         [ +  - ]:          1 :             VSIFSeekL(fpL, 0, SEEK_END);
    1605         [ +  - ]:          1 :             vsi_l_offset nFileSize = VSIFTellL(fpL);
    1606                 :          1 :             vsi_l_offset nOffset = nFileSize;
    1607                 :          1 :             bool bTerminatingEOL = true;
    1608         [ +  - ]:          1 :             while( nOffset > 0 )
    1609                 :            :             {
    1610         [ +  - ]:          1 :                 VSIFSeekL(fpL, nOffset - 1, SEEK_SET);
    1611                 :          1 :                 char ch = '\0';
    1612         [ +  - ]:          1 :                 VSIFReadL(&ch, 1, 1, fpL);
    1613         [ +  + ]:          1 :                 if( bTerminatingEOL )
    1614                 :            :                 {
    1615 [ +  - ][ +  + ]:          1 :                     if( !(ch == '\r' || ch == '\n') )
    1616                 :            :                     {
    1617                 :          1 :                         bTerminatingEOL = false;
    1618                 :            :                     }
    1619                 :            :                 }
    1620                 :            :                 else
    1621                 :            :                 {
    1622 [ +  - ][ +  + ]:          1 :                     if( ch == '\r' || ch == '\n' )
    1623                 :          1 :                         break;
    1624                 :            :                 }
    1625                 :          1 :                 nOffset --;
    1626                 :            :             }
    1627                 :            : 
    1628                 :            :             // If it is "eof;..." then overwrite it with new content
    1629         [ +  - ]:          1 :             const char* pszLine = CPLReadLineL(fpL);
    1630 [ +  - ][ +  + ]:          1 :             if( pszLine != NULL && STARTS_WITH(pszLine, "eof;") )
    1631                 :            :             {
    1632         [ +  - ]:          1 :                 VSIFSeekL(fpL, nOffset, SEEK_SET);
    1633 [ +  - ][ +  - ]:          1 :                 VSIFTruncateL(fpL, VSIFTellL(fpL));
    1634                 :            :             }
    1635         [ +  - ]:          1 :             else if( nFileSize > 0 )
    1636                 :            :             {
    1637                 :            :                 // Otherwise make sure the file ends with an eol character
    1638         [ +  - ]:          1 :                 VSIFSeekL(fpL, nFileSize - 1, SEEK_SET);
    1639                 :          1 :                 char ch = '\0';
    1640         [ +  - ]:          1 :                 VSIFReadL(&ch, 1, 1, fpL);
    1641         [ +  - ]:          1 :                 VSIFSeekL(fpL, nFileSize, SEEK_SET);
    1642 [ +  - ][ -  + ]:          1 :                 if( !(ch == '\r' || ch == '\n') )
    1643                 :            :                 {
    1644                 :          0 :                     ch = '\n';
    1645         [ #  # ]:          1 :                     VSIFWriteL(&ch, 1, 1, fpL);
    1646                 :            :                 }
    1647                 :            :             }
    1648                 :            :         }
    1649                 :            :     }
    1650                 :            :     else
    1651                 :            :     {
    1652 [ +  - ][ +  - ]:          1 :         CPLString osExtension = CSLFetchNameValueDef(papszOptions, "EXTENSION", "x10");
    1653                 :            :         CPLString osFilename = CPLFormFilename(m_osFilename, pszLayerName,
    1654 [ +  - ][ +  - ]:          1 :                                                osExtension);
         [ +  - ][ +  - ]
    1655 [ +  - ][ +  - ]:          1 :         fpL = VSIFOpenL(osFilename, "wb");
    1656         [ +  + ]:          1 :         if( fpL == NULL )
    1657                 :            :         {
    1658                 :            :             CPLError( CE_Failure, CPLE_FileIO, "Cannot create %s",
    1659 [ +  - ][ +  - ]:          1 :                       osFilename.c_str() );
    1660                 :          1 :             return NULL;
    1661 [ +  - ][ +  + ]:          1 :         }
         [ +  - ][ +  + ]
    1662                 :            :     }
    1663                 :            : 
    1664         [ +  - ]:          1 :     GetLayerCount();
    1665                 :            : 
    1666 [ +  + ][ +  + ]:          1 :     if( m_nLayerCount == 0 || !m_bSingleFile )
    1667                 :            :     {
    1668 [ +  - ][ -  + ]:          1 :         if( !OGRVDVWriteHeader(fpL, papszOptions) )
    1669                 :            :         {
    1670         [ #  # ]:          0 :             if( !m_bSingleFile )
    1671         [ #  # ]:          0 :                 VSIFCloseL(fpL);
    1672                 :          0 :             return NULL;
    1673                 :            :         }
    1674                 :            :     }
    1675                 :            : 
    1676                 :          1 :     m_bMustWriteEof = true;
    1677                 :            : 
    1678                 :            :     OGRVDVWriterLayer* poLayer = new OGRVDVWriterLayer(this,
    1679                 :            :                                                        pszLayerName,
    1680                 :            :                                                        fpL,
    1681                 :          1 :                                                        !m_bSingleFile,
    1682                 :            :                                                        poVDV452Table,
    1683                 :            :                                                        osVDV452Lang,
    1684 [ +  - ][ +  - ]:          1 :                                                        bProfileStrict);
    1685                 :            :     m_papoLayers = static_cast<OGRLayer**>(CPLRealloc(
    1686         [ +  - ]:          1 :                 m_papoLayers, sizeof(OGRLayer*) * (m_nLayerCount + 1) ));
    1687                 :          1 :     m_papoLayers[m_nLayerCount] = poLayer;
    1688                 :          1 :     m_nLayerCount ++;
    1689                 :            : 
    1690 [ +  + ][ +  + ]:          1 :     if( eGType == wkbPoint && poVDV452Table != NULL &&
         [ +  + ][ +  - ]
    1691                 :          1 :         (EQUAL(pszLayerName, "STOP") || EQUAL(pszLayerName, "REC_ORT")) )
    1692                 :            :     {
    1693 [ +  - ][ +  - ]:          1 :         poLayer->GetLayerDefn()->SetGeomType(wkbPoint);
    1694                 :            :     }
    1695                 :            : 
    1696 [ +  - ][ +  + ]:          1 :     if( bCreateAllFields && poVDV452Table != NULL )
    1697                 :            :     {
    1698 [ +  - ][ +  + ]:          1 :         for(size_t i=0; i<poVDV452Table->aosFields.size();i++)
    1699                 :            :         {
    1700         [ +  - ]:          1 :             const char* pszFieldName = (osVDV452Lang == "en") ?
    1701         [ +  - ]:          1 :                             poVDV452Table->aosFields[i].osEnglishName.c_str() :
    1702 [ +  + ][ +  - ]:          1 :                             poVDV452Table->aosFields[i].osGermanName.c_str();
         [ +  - ][ +  - ]
    1703                 :          1 :             OGRFieldType eType = OFTString;
    1704         [ +  - ]:          1 :             int nWidth = poVDV452Table->aosFields[i].nWidth;
    1705 [ +  - ][ +  - ]:          1 :             if( poVDV452Table->aosFields[i].osType == "num" ||
         [ +  + ][ -  + ]
                 [ +  + ]
    1706 [ +  - ][ +  - ]:          1 :                 poVDV452Table->aosFields[i].osType == "boolean" )
    1707                 :          1 :                 eType = OFTInteger;
    1708 [ +  - ][ +  - ]:          1 :             if( poVDV452Table->aosFields[i].osType == "num" )
                 [ +  + ]
    1709                 :            :             {
    1710                 :            :                 /* VDV 451 is without sign */
    1711                 :          1 :                 nWidth ++;
    1712         [ +  + ]:          1 :                 if( nWidth >= 10 )
    1713                 :          1 :                     eType = OFTInteger64;
    1714                 :            :             }
    1715         [ +  - ]:          1 :             OGRFieldDefn oField( pszFieldName, eType );
    1716 [ +  - ][ +  - ]:          1 :             if( poVDV452Table->aosFields[i].osType == "boolean" )
                 [ -  + ]
    1717         [ #  # ]:          0 :                 oField.SetSubType(OFSTBoolean);
    1718         [ +  - ]:          1 :             oField.SetWidth( nWidth );
    1719         [ +  - ]:          1 :             poLayer->CreateField(&oField);
    1720         [ +  - ]:          1 :         }
    1721                 :            :     }
    1722                 :            : 
    1723         [ +  - ]:          1 :     return poLayer;
    1724                 :            : }
    1725                 :            : 
    1726                 :            : /************************************************************************/
    1727                 :            : /*                       SetCurrentWriterLayer()                        */
    1728                 :            : /************************************************************************/
    1729                 :            : 
    1730                 :          1 : void OGRVDVDataSource::SetCurrentWriterLayer(OGRVDVWriterLayer* poLayer)
    1731                 :            : {
    1732         [ +  + ]:          1 :     if( !m_bSingleFile )
    1733                 :          1 :         return;
    1734 [ +  + ][ +  + ]:          1 :     if( m_poCurrentWriterLayer != NULL && m_poCurrentWriterLayer != poLayer )
    1735                 :            :     {
    1736                 :          1 :         m_poCurrentWriterLayer->StopAsCurrentLayer();
    1737                 :            :     }
    1738                 :          1 :     m_poCurrentWriterLayer = poLayer;
    1739                 :            : }
    1740                 :            : 
    1741                 :            : /************************************************************************/
    1742                 :            : /*                           TestCapability()                           */
    1743                 :            : /************************************************************************/
    1744                 :            : 
    1745                 :          1 : int OGRVDVDataSource::TestCapability( const char * pszCap )
    1746                 :            : 
    1747                 :            : {
    1748         [ +  + ]:          1 :     if( EQUAL(pszCap,ODsCCreateLayer) )
    1749                 :          1 :         return m_bUpdate;
    1750                 :          1 :     return FALSE;
    1751                 :            : }
    1752                 :            : 
    1753                 :            : /************************************************************************/
    1754                 :            : /*                                 Create()                             */
    1755                 :            : /************************************************************************/
    1756                 :            : 
    1757                 :          1 : GDALDataset* OGRVDVDataSource::Create( const char * pszName,
    1758                 :            :                                         int /*nXSize*/, int /*nYSize*/, int /*nBands*/,
    1759                 :            :                                         GDALDataType /*eType*/,
    1760                 :            :                                         char ** papszOptions )
    1761                 :            : 
    1762                 :            : {
    1763                 :            : /* -------------------------------------------------------------------- */
    1764                 :            : /*      First, ensure there isn't any such file yet.                    */
    1765                 :            : /* -------------------------------------------------------------------- */
    1766                 :            :     VSIStatBufL sStatBuf;
    1767         [ +  + ]:          1 :     if( VSIStatL( pszName, &sStatBuf ) == 0 )
    1768                 :            :     {
    1769                 :            :         CPLError( CE_Failure, CPLE_AppDefined,
    1770                 :            :                   "It seems a file system object called '%s' already exists.",
    1771                 :          1 :                   pszName );
    1772                 :            : 
    1773                 :          1 :         return NULL;
    1774                 :            :     }
    1775                 :            : 
    1776                 :          1 :     const bool bSingleFile = CPLFetchBool(papszOptions, "SINGLE_FILE", true);
    1777         [ +  + ]:          1 :     if( !bSingleFile )
    1778                 :            :     {
    1779         [ +  + ]:          1 :         if( VSIMkdir( pszName, 0755 ) != 0 )
    1780                 :            :         {
    1781                 :            :             CPLError( CE_Failure, CPLE_AppDefined,
    1782                 :            :                       "Failed to create directory %s:\n%s",
    1783                 :          1 :                       pszName, VSIStrerror( errno ) );
    1784                 :          1 :             return NULL;
    1785                 :            :         }
    1786                 :            :     }
    1787                 :            : 
    1788                 :          1 :     VSILFILE* fpL = NULL;
    1789         [ +  + ]:          1 :     if( bSingleFile )
    1790                 :            :     {
    1791                 :          1 :         fpL = VSIFOpenL(pszName, "wb");
    1792         [ +  + ]:          1 :         if( fpL == NULL )
    1793                 :            :         {
    1794                 :          1 :             CPLError( CE_Failure, CPLE_FileIO, "Cannot create %s", pszName );
    1795                 :          1 :             return NULL;
    1796                 :            :         }
    1797                 :            :     }
    1798                 :            :     OGRVDVDataSource* poDS = new OGRVDVDataSource(pszName, fpL, true,
    1799                 :            :                                                   bSingleFile,
    1800         [ +  - ]:          1 :                                                   true /* new */);
    1801                 :          1 :     return poDS;
    1802                 :            : }
    1803                 :            : 
    1804                 :            : /************************************************************************/
    1805                 :            : /*                         RegisterOGRVDV()                             */
    1806                 :            : /************************************************************************/
    1807                 :            : 
    1808                 :          1 : void RegisterOGRVDV()
    1809                 :            : 
    1810                 :            : {
    1811         [ +  + ]:          1 :     if( GDALGetDriverByName( "VDV" ) != NULL )
    1812                 :          1 :         return;
    1813                 :            : 
    1814         [ +  - ]:          1 :     GDALDriver *poDriver = new GDALDriver();
    1815                 :            : 
    1816                 :          1 :     poDriver->SetDescription( "VDV" );
    1817                 :          1 :     poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
    1818                 :            :     poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    1819                 :          1 :                                "VDV-451/VDV-452/INTREST Data Format" );
    1820                 :          1 :     poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drv_vdv.html" );
    1821                 :          1 :     poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "txt x10");
    1822                 :          1 :     poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1823                 :            :     poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES,
    1824                 :          1 :                                "Integer Integer64 String" );
    1825                 :            : 
    1826                 :            :     poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    1827                 :            : "<CreationOptionList>"
    1828                 :            : "  <Option name='SINGLE_FILE' type='boolean' description='Whether several layers "
    1829                 :            : "should be put in the same file. If no, the name is assumed to be a directory name' default='YES'/>"
    1830                 :          1 : "</CreationOptionList>");
    1831                 :            : 
    1832                 :            :     poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
    1833                 :            : "<LayerCreationOptionList>"
    1834                 :            : "  <Option name='EXTENSION' type='string' description='Layer file extension. Only used for SINGLE_FILE=NO' default='x10'/>"
    1835                 :            : "  <Option name='PROFILE' type='string-select' description='Profile' default='GENERIC'>"
    1836                 :            : "       <Value>GENERIC</Value>"
    1837                 :            : "       <Value>VDV-452</Value>"
    1838                 :            : "       <Value>VDV-452-ENGLISH</Value>"
    1839                 :            : "       <Value>VDV-452-GERMAN</Value>"
    1840                 :            : "  </Option>"
    1841                 :            : "  <Option name='PROFILE_STRICT' type='boolean' description='Whether checks of profile should be strict' default='NO'/>"
    1842                 :            : "  <Option name='CREATE_ALL_FIELDS' type='boolean' description="
    1843                 :            :     "'Whether all fields of predefined profiles should be created at layer creation' default='YES'/>"
    1844                 :            : "  <Option name='STANDARD_HEADER' type='boolean' description='Whether to write standard header fields' default='YES'/>"
    1845                 :            : "  <Option name='HEADER_SRC' type='string' description='Value of the src header field' default='UNKNOWN'/>"
    1846                 :            : "  <Option name='HEADER_SRC_DATE' type='string' description='Value of the date of the src header field as DD.MM.YYYY'/>"
    1847                 :            : "  <Option name='HEADER_SRC_TIME' type='string' description='Value of the time of the src header field as HH.MM.SS'/>"
    1848                 :            : "  <Option name='HEADER_CHS' type='string' description='Value of the chs header field' default='ISO8859-1'/>"
    1849                 :            : "  <Option name='HEADER_VER' type='string' description='Value of the ver header field' default='1.4'/>"
    1850                 :            : "  <Option name='HEADER_IFV' type='string' description='Value of the ifv header field' default='1.4'/>"
    1851                 :            : "  <Option name='HEADER_DVE' type='string' description='Value of the dve header field' default='1.4'/>"
    1852                 :            : "  <Option name='HEADER_FFT' type='string' description='Value of the fft header field' default=''/>"
    1853                 :            : "  <Option name='HEADER_*' type='string' description='Value of another header field'/>"
    1854                 :          1 : "</LayerCreationOptionList>");
    1855                 :          1 :     poDriver->pfnIdentify = OGRVDVDriverIdentify;
    1856                 :          1 :     poDriver->pfnOpen = OGRVDVDataSource::Open;
    1857                 :          1 :     poDriver->pfnCreate = OGRVDVDataSource::Create;
    1858                 :            : 
    1859                 :          1 :     GetGDALDriverManager()->RegisterDriver( poDriver );
    1860                 :            : }

Generated by: LCOV version 1.9