LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gpx - ogrgpxlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 898 672 74.8 %
Date: 2010-01-09 Functions: 30 24 80.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgpxlayer.cpp 17753 2009-10-04 18:41:53Z rouault $
       3                 :  *
       4                 :  * Project:  GPX Translator
       5                 :  * Purpose:  Implements OGRGPXLayer class.
       6                 :  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2007, Even Rouault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_gpx.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_string.h"
      33                 : #include "cpl_minixml.h"
      34                 : #include "ogr_p.h"
      35                 : 
      36                 : CPL_CVSID("$Id: ogrgpxlayer.cpp 17753 2009-10-04 18:41:53Z rouault $");
      37                 : 
      38                 : /************************************************************************/
      39                 : /*                            OGRGPXLayer()                             */
      40                 : /*                                                                      */
      41                 : /*      Note that the OGRGPXLayer assumes ownership of the passed       */
      42                 : /*      file pointer.                                                   */
      43                 : /************************************************************************/
      44                 : 
      45              19 : OGRGPXLayer::OGRGPXLayer( const char* pszFilename,
      46                 :                           const char* pszLayerName,
      47                 :                           GPXGeometryType gpxGeomType,
      48                 :                           OGRGPXDataSource* poDS,
      49              19 :                           int bWriteMode)
      50                 : 
      51                 : {
      52              19 :     const char* gpxVersion = poDS->GetVersion();
      53                 : 
      54                 :     int i;
      55                 : 
      56              19 :     eof = FALSE;
      57              19 :     nNextFID = 0;
      58                 :     
      59              19 :     this->poDS = poDS;
      60              19 :     this->bWriteMode = bWriteMode;
      61              19 :     this->gpxGeomType = gpxGeomType;
      62                 :     
      63              19 :     pszElementToScan = pszLayerName;
      64                 :     
      65              19 :     nMaxLinks = atoi(CPLGetConfigOption("GPX_N_MAX_LINKS", "2"));
      66              19 :     if (nMaxLinks < 0)
      67               0 :         nMaxLinks = 2;
      68              19 :     if (nMaxLinks > 100)
      69               0 :         nMaxLinks = 100;
      70                 : 
      71              19 :     nFeatures = 0;
      72                 :     
      73              19 :     bEleAs25D =  CSLTestBoolean(CPLGetConfigOption("GPX_ELE_AS_25D", "NO"));
      74                 :     
      75              19 :     int bShortNames  = CSLTestBoolean(CPLGetConfigOption("GPX_SHORT_NAMES", "NO"));
      76                 :     
      77              19 :     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
      78              19 :     poFeatureDefn->Reference();
      79                 :     
      80              19 :     if (gpxGeomType == GPX_TRACK_POINT)
      81                 :     {
      82                 :         /* Don't move this code. This fields must be number 0, 1 and 2 */
      83                 :         /* in order to make OGRGPXLayer::startElementCbk work */
      84               3 :         OGRFieldDefn oFieldTrackFID("track_fid", OFTInteger );
      85               3 :         poFeatureDefn->AddFieldDefn( &oFieldTrackFID );
      86                 :         
      87               3 :         OGRFieldDefn oFieldTrackSegID((bShortNames) ? "trksegid" : "track_seg_id", OFTInteger );
      88               3 :         poFeatureDefn->AddFieldDefn( &oFieldTrackSegID );
      89                 :         
      90               3 :         OGRFieldDefn oFieldTrackSegPointID((bShortNames) ? "trksegptid" : "track_seg_point_id", OFTInteger );
      91               3 :         poFeatureDefn->AddFieldDefn( &oFieldTrackSegPointID );
      92                 :     }
      93              16 :     else if (gpxGeomType == GPX_ROUTE_POINT)
      94                 :     {
      95                 :         /* Don't move this code. See above */
      96               3 :         OGRFieldDefn oFieldRouteFID("route_fid", OFTInteger );
      97               3 :         poFeatureDefn->AddFieldDefn( &oFieldRouteFID );
      98                 :         
      99               3 :         OGRFieldDefn oFieldRoutePointID((bShortNames) ? "rteptid" : "route_point_id", OFTInteger );
     100               3 :         poFeatureDefn->AddFieldDefn( &oFieldRoutePointID );
     101                 :     }
     102                 : 
     103              30 :     if (gpxGeomType == GPX_WPT ||
     104                 :         gpxGeomType == GPX_TRACK_POINT ||
     105                 :         gpxGeomType == GPX_ROUTE_POINT)
     106                 :     {
     107              11 :         poFeatureDefn->SetGeomType((bEleAs25D) ? wkbPoint25D : wkbPoint);
     108                 :         /* Position info */
     109                 :         
     110              11 :         OGRFieldDefn oFieldEle("ele", OFTReal );
     111              11 :         poFeatureDefn->AddFieldDefn( &oFieldEle );
     112                 :         
     113              11 :         OGRFieldDefn oFieldTime("time", OFTDateTime );
     114              11 :         poFeatureDefn->AddFieldDefn( &oFieldTime );
     115                 :         
     116              11 :         if (gpxGeomType == GPX_TRACK_POINT &&
     117                 :             gpxVersion && strcmp(gpxVersion, "1.0") == 0)
     118                 :         {
     119               0 :             OGRFieldDefn oFieldCourse("course", OFTReal );
     120               0 :             poFeatureDefn->AddFieldDefn( &oFieldCourse );
     121                 :             
     122               0 :             OGRFieldDefn oFieldSpeed("speed", OFTReal );
     123               0 :             poFeatureDefn->AddFieldDefn( &oFieldSpeed );
     124                 :         }
     125                 :         
     126              11 :         OGRFieldDefn oFieldMagVar("magvar", OFTReal );
     127              11 :         poFeatureDefn->AddFieldDefn( &oFieldMagVar );
     128                 :     
     129              11 :         OGRFieldDefn oFieldGeoidHeight("geoidheight", OFTReal );
     130              11 :         poFeatureDefn->AddFieldDefn( &oFieldGeoidHeight );
     131                 :             
     132                 :         /* Description info */
     133                 :         
     134              11 :         OGRFieldDefn oFieldName("name", OFTString );
     135              11 :         poFeatureDefn->AddFieldDefn( &oFieldName );
     136                 :         
     137              11 :         OGRFieldDefn oFieldCmt("cmt", OFTString );
     138              11 :         poFeatureDefn->AddFieldDefn( &oFieldCmt );
     139                 :         
     140              11 :         OGRFieldDefn oFieldDesc("desc", OFTString );
     141              11 :         poFeatureDefn->AddFieldDefn( &oFieldDesc );
     142                 :         
     143              11 :         OGRFieldDefn oFieldSrc("src", OFTString );
     144              11 :         poFeatureDefn->AddFieldDefn( &oFieldSrc );
     145                 :         
     146              11 :         if (gpxVersion && strcmp(gpxVersion, "1.0") == 0)
     147                 :         {
     148               0 :             OGRFieldDefn oFieldUrl("url", OFTString );
     149               0 :             poFeatureDefn->AddFieldDefn( &oFieldUrl );
     150                 :             
     151               0 :             OGRFieldDefn oFieldUrlName("urlname", OFTString );
     152               0 :             poFeatureDefn->AddFieldDefn( &oFieldUrlName );
     153                 :         }
     154                 :         else
     155                 :         {
     156              33 :             for(i=1;i<=nMaxLinks;i++)
     157                 :             {
     158                 :                 char szFieldName[32];
     159              22 :                 sprintf(szFieldName, "link%d_href", i);
     160              22 :                 OGRFieldDefn oFieldLinkHref( szFieldName, OFTString );
     161              22 :                 poFeatureDefn->AddFieldDefn( &oFieldLinkHref );
     162                 :                 
     163              22 :                 sprintf(szFieldName, "link%d_text", i);
     164              22 :                 OGRFieldDefn oFieldLinkText( szFieldName, OFTString );
     165              22 :                 poFeatureDefn->AddFieldDefn( &oFieldLinkText );
     166                 :                 
     167              22 :                 sprintf(szFieldName, "link%d_type", i);
     168              22 :                 OGRFieldDefn oFieldLinkType( szFieldName, OFTString );
     169              22 :                 poFeatureDefn->AddFieldDefn( &oFieldLinkType );
     170                 :             }
     171                 :         }
     172                 :         
     173              11 :         OGRFieldDefn oFieldSym("sym", OFTString );
     174              11 :         poFeatureDefn->AddFieldDefn( &oFieldSym );
     175                 :         
     176              11 :         OGRFieldDefn oFieldType("type", OFTString );
     177              11 :         poFeatureDefn->AddFieldDefn( &oFieldType );
     178                 :     
     179                 :         /* Accuracy info */
     180                 :         
     181              11 :         OGRFieldDefn oFieldFix("fix", OFTString );
     182              11 :         poFeatureDefn->AddFieldDefn( &oFieldFix );
     183                 :         
     184              11 :         OGRFieldDefn oFieldSat("sat", OFTInteger );
     185              11 :         poFeatureDefn->AddFieldDefn( &oFieldSat );
     186                 :         
     187              11 :         OGRFieldDefn oFieldHdop("hdop", OFTReal );
     188              11 :         poFeatureDefn->AddFieldDefn( &oFieldHdop );
     189                 :         
     190              11 :         OGRFieldDefn oFieldVdop("vdop", OFTReal );
     191              11 :         poFeatureDefn->AddFieldDefn( &oFieldVdop );
     192                 :         
     193              11 :         OGRFieldDefn oFieldPdop("pdop", OFTReal );
     194              11 :         poFeatureDefn->AddFieldDefn( &oFieldPdop );
     195                 :         
     196              11 :         OGRFieldDefn oFieldAgeofgpsdata("ageofdgpsdata", OFTReal );
     197              11 :         poFeatureDefn->AddFieldDefn( &oFieldAgeofgpsdata );
     198                 :         
     199              11 :         OGRFieldDefn oFieldDgpsid("dgpsid", OFTInteger );
     200              11 :         poFeatureDefn->AddFieldDefn( &oFieldDgpsid );
     201                 :     }
     202                 :     else
     203                 :     {
     204               8 :         if (gpxGeomType == GPX_TRACK)
     205               4 :             poFeatureDefn->SetGeomType((bEleAs25D) ? wkbMultiLineString25D : wkbMultiLineString);
     206                 :         else
     207               4 :             poFeatureDefn->SetGeomType((bEleAs25D) ? wkbLineString25D : wkbLineString);
     208                 :         
     209               8 :         OGRFieldDefn oFieldName("name", OFTString );
     210               8 :         poFeatureDefn->AddFieldDefn( &oFieldName );
     211                 :         
     212               8 :         OGRFieldDefn oFieldCmt("cmt", OFTString );
     213               8 :         poFeatureDefn->AddFieldDefn( &oFieldCmt );
     214                 :         
     215               8 :         OGRFieldDefn oFieldDesc("desc", OFTString );
     216               8 :         poFeatureDefn->AddFieldDefn( &oFieldDesc );
     217                 :         
     218               8 :         OGRFieldDefn oFieldSrc("src", OFTString );
     219               8 :         poFeatureDefn->AddFieldDefn( &oFieldSrc );
     220                 :         
     221              24 :         for(i=1;i<=nMaxLinks;i++)
     222                 :         {
     223                 :             char szFieldName[32];
     224              16 :             sprintf(szFieldName, "link%d_href", i);
     225              16 :             OGRFieldDefn oFieldLinkHref( szFieldName, OFTString );
     226              16 :             poFeatureDefn->AddFieldDefn( &oFieldLinkHref );
     227                 :             
     228              16 :             sprintf(szFieldName, "link%d_text", i);
     229              16 :             OGRFieldDefn oFieldLinkText( szFieldName, OFTString );
     230              16 :             poFeatureDefn->AddFieldDefn( &oFieldLinkText );
     231                 :             
     232              16 :             sprintf(szFieldName, "link%d_type", i);
     233              16 :             OGRFieldDefn oFieldLinkType( szFieldName, OFTString );
     234              16 :             poFeatureDefn->AddFieldDefn( &oFieldLinkType );
     235                 :         }
     236                 :         
     237               8 :         OGRFieldDefn oFieldNumber("number", OFTInteger );
     238               8 :         poFeatureDefn->AddFieldDefn( &oFieldNumber );
     239                 :         
     240               8 :         OGRFieldDefn oFieldType("type", OFTString );
     241               8 :         poFeatureDefn->AddFieldDefn( &oFieldType );
     242                 :     }
     243                 :     
     244                 :     /* Number of 'standard' GPX attributes */
     245              19 :     nGPXFields = poFeatureDefn->GetFieldCount();
     246                 :    
     247              19 :     ppoFeatureTab = NULL;
     248              19 :     nFeatureTabIndex = 0;
     249              19 :     nFeatureTabLength = 0;
     250              19 :     pszSubElementName = NULL;
     251              19 :     pszSubElementValue = NULL;
     252              19 :     nSubElementValueLen = 0;
     253              19 :     bStopParsing = FALSE;
     254                 : 
     255                 :     poSRS = new OGRSpatialReference("GEOGCS[\"WGS 84\", "
     256                 :         "   DATUM[\"WGS_1984\","
     257                 :         "       SPHEROID[\"WGS 84\",6378137,298.257223563,"
     258                 :         "           AUTHORITY[\"EPSG\",\"7030\"]],"
     259                 :         "           AUTHORITY[\"EPSG\",\"6326\"]],"
     260                 :         "       PRIMEM[\"Greenwich\",0,"
     261                 :         "           AUTHORITY[\"EPSG\",\"8901\"]],"
     262                 :         "       UNIT[\"degree\",0.01745329251994328,"
     263                 :         "           AUTHORITY[\"EPSG\",\"9122\"]],"
     264              19 :         "           AUTHORITY[\"EPSG\",\"4326\"]]");
     265                 : 
     266              19 :     poFeature = NULL;
     267                 : 
     268                 : #ifdef HAVE_EXPAT
     269              19 :     oParser = NULL;
     270                 : #endif
     271                 : 
     272              19 :     if (bWriteMode == FALSE)
     273                 :     {
     274              15 :         fpGPX = VSIFOpenL( pszFilename, "r" );
     275              15 :         if( fpGPX == NULL )
     276                 :         {
     277               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s", pszFilename);
     278               0 :             return;
     279                 :         }
     280                 : 
     281              15 :         if (poDS->GetUseExtensions() ||
     282                 :             CSLTestBoolean(CPLGetConfigOption("GPX_USE_EXTENSIONS", "FALSE")))
     283                 :         {
     284              10 :             LoadExtensionsSchema();
     285                 :         }
     286                 :     }
     287                 :     else
     288               4 :         fpGPX = NULL;
     289                 : 
     290              19 :     ResetReading();
     291               0 : }
     292                 : 
     293                 : /************************************************************************/
     294                 : /*                            ~OGRGPXLayer()                            */
     295                 : /************************************************************************/
     296                 : 
     297              38 : OGRGPXLayer::~OGRGPXLayer()
     298                 : 
     299                 : {
     300                 : #ifdef HAVE_EXPAT
     301              19 :     if (oParser)
     302              15 :         XML_ParserFree(oParser);
     303                 : #endif
     304              19 :     poFeatureDefn->Release();
     305                 :     
     306              19 :     if( poSRS != NULL )
     307              19 :         poSRS->Release();
     308                 : 
     309              19 :     CPLFree(pszSubElementName);
     310              19 :     CPLFree(pszSubElementValue);
     311                 : 
     312                 :     int i;
     313              24 :     for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
     314               5 :         delete ppoFeatureTab[i];
     315              19 :     CPLFree(ppoFeatureTab);
     316                 : 
     317              19 :     if (poFeature)
     318               0 :         delete poFeature;
     319                 : 
     320              19 :     if (fpGPX)
     321              15 :         VSIFCloseL( fpGPX );
     322              38 : }
     323                 : 
     324                 : #ifdef HAVE_EXPAT
     325                 : 
     326            1414 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName, const char **ppszAttr)
     327                 : {
     328            1414 :     ((OGRGPXLayer*)pUserData)->startElementCbk(pszName, ppszAttr);
     329            1414 : }
     330                 : 
     331            1414 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
     332                 : {
     333            1414 :     ((OGRGPXLayer*)pUserData)->endElementCbk(pszName);
     334            1414 : }
     335                 : 
     336            3913 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
     337                 : {
     338            3913 :     ((OGRGPXLayer*)pUserData)->dataHandlerCbk(data, nLen);
     339            3913 : }
     340                 : 
     341                 : #endif
     342                 : 
     343                 : /************************************************************************/
     344                 : /*                            ResetReading()                            */
     345                 : /************************************************************************/
     346                 : 
     347              48 : void OGRGPXLayer::ResetReading()
     348                 : 
     349                 : {
     350              48 :     eof = FALSE;
     351              48 :     nNextFID = 0;
     352              48 :     if (fpGPX)
     353                 :     {
     354              44 :         VSIFSeekL( fpGPX, 0, SEEK_SET );
     355                 : #ifdef HAVE_EXPAT
     356              44 :         if (oParser)
     357              29 :             XML_ParserFree(oParser);
     358                 : 
     359              44 :         oParser = OGRCreateExpatXMLParser();
     360              44 :         XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
     361              44 :         XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
     362              44 :         XML_SetUserData(oParser, this);
     363                 : #endif
     364                 :     }
     365              48 :     hasFoundLat = FALSE;
     366              48 :     hasFoundLon = FALSE;
     367              48 :     inInterestingElement = FALSE;
     368              48 :     CPLFree(pszSubElementName);
     369              48 :     pszSubElementName = NULL;
     370              48 :     CPLFree(pszSubElementValue);
     371              48 :     pszSubElementValue = NULL;
     372              48 :     nSubElementValueLen = 0;
     373                 :     
     374                 :     int i;
     375              48 :     for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
     376               0 :         delete ppoFeatureTab[i];
     377              48 :     CPLFree(ppoFeatureTab);
     378              48 :     nFeatureTabIndex = 0;
     379              48 :     nFeatureTabLength = 0;
     380              48 :     ppoFeatureTab = NULL;
     381              48 :     if (poFeature)
     382               0 :         delete poFeature;
     383              48 :     poFeature = NULL;
     384              48 :     multiLineString = NULL;
     385              48 :     lineString = NULL;
     386                 : 
     387              48 :     depthLevel = 0;
     388              48 :     interestingDepthLevel = 0;
     389                 :     
     390              48 :     trkFID = trkSegId = trkSegPtId = 0;
     391              48 :     rteFID = rtePtId = 0;
     392              48 : }
     393                 : 
     394                 : #ifdef HAVE_EXPAT
     395                 : 
     396                 : /************************************************************************/
     397                 : /*                        startElementCbk()                            */
     398                 : /************************************************************************/
     399                 : 
     400                 : /** Replace ':' from XML NS element name by '_' more OGR friendly */
     401              48 : static char* OGRGPX_GetOGRCompatibleTagName(const char* pszName)
     402                 : {
     403              48 :     char* pszModName = CPLStrdup(pszName);
     404                 :     int i;
     405             704 :     for(i=0;pszModName[i] != 0;i++)
     406                 :     {
     407             656 :         if (pszModName[i] == ':')
     408              48 :             pszModName[i] = '_';
     409                 :     }
     410              48 :     return pszModName;
     411                 : }
     412                 : 
     413               0 : void OGRGPXLayer::AddStrToSubElementValue(const char* pszStr)
     414                 : {
     415               0 :     int len = strlen(pszStr);
     416                 :     char* pszNewSubElementValue = (char*)
     417               0 :             VSIRealloc(pszSubElementValue, nSubElementValueLen + len + 1);
     418               0 :     if (pszNewSubElementValue == NULL)
     419                 :     {
     420               0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
     421               0 :         XML_StopParser(oParser, XML_FALSE);
     422               0 :         bStopParsing = TRUE;
     423               0 :         return;
     424                 :     }
     425               0 :     pszSubElementValue = pszNewSubElementValue;
     426               0 :     memcpy(pszSubElementValue + nSubElementValueLen, pszStr, len);
     427               0 :     nSubElementValueLen += len;
     428                 : }
     429                 : 
     430            1414 : void OGRGPXLayer::startElementCbk(const char *pszName, const char **ppszAttr)
     431                 : {
     432                 :     int i;
     433                 : 
     434            1414 :     if (bStopParsing) return;
     435                 : 
     436            1414 :     nWithoutEventCounter = 0;
     437                 : 
     438            1476 :     if ((gpxGeomType == GPX_WPT && strcmp(pszName, "wpt") == 0) ||
     439                 :         (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rtept") == 0) ||
     440                 :         (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkpt") == 0))
     441                 :     {
     442              62 :         interestingDepthLevel = depthLevel;
     443                 : 
     444              62 :         if (poFeature)
     445               0 :             delete poFeature;
     446                 : 
     447              62 :         poFeature = new OGRFeature( poFeatureDefn );
     448              62 :         inInterestingElement = TRUE;
     449              62 :         hasFoundLat = FALSE;
     450              62 :         hasFoundLon = FALSE;
     451              62 :         inExtensions = FALSE;
     452              62 :         inLink = FALSE;
     453              62 :         iCountLink = 0;
     454                 : 
     455             186 :         for (i = 0; ppszAttr[i]; i += 2)
     456                 :         {
     457             124 :             if (strcmp(ppszAttr[i], "lat") == 0)
     458                 :             {
     459              62 :                 hasFoundLat = TRUE;
     460              62 :                 latVal = CPLAtof(ppszAttr[i + 1]);
     461                 :             }
     462              62 :             else if (strcmp(ppszAttr[i], "lon") == 0)
     463                 :             {
     464              62 :                 hasFoundLon = TRUE;
     465              62 :                 lonVal = CPLAtof(ppszAttr[i + 1]);
     466                 :             }
     467                 :         }
     468                 : 
     469              62 :         if (hasFoundLat && hasFoundLon)
     470                 :         {
     471              62 :             poFeature->SetFID( nNextFID++ );
     472              62 :             poFeature->SetGeometryDirectly( new OGRPoint( lonVal, latVal ) );
     473                 : 
     474              62 :             if (gpxGeomType == GPX_ROUTE_POINT)
     475                 :             {
     476               6 :                 rtePtId++;
     477               6 :                 poFeature->SetField( 0, rteFID-1);
     478               6 :                 poFeature->SetField( 1, rtePtId-1);
     479                 :             }
     480              56 :             else if (gpxGeomType == GPX_TRACK_POINT)
     481                 :             {
     482               8 :                 trkSegPtId++;
     483                 : 
     484               8 :                 poFeature->SetField( 0, trkFID-1);
     485               8 :                 poFeature->SetField( 1, trkSegId-1);
     486               8 :                 poFeature->SetField( 2, trkSegPtId-1);
     487                 :             }
     488                 :         }
     489                 :     }
     490            1361 :     else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trk") == 0)
     491                 :     {
     492               9 :         interestingDepthLevel = depthLevel;
     493                 : 
     494               9 :         if (poFeature)
     495               0 :             delete poFeature;
     496               9 :         inExtensions = FALSE;
     497               9 :         inLink = FALSE;
     498               9 :         iCountLink = 0;
     499               9 :         poFeature = new OGRFeature( poFeatureDefn );
     500               9 :         inInterestingElement = TRUE;
     501                 : 
     502              18 :         multiLineString = new OGRMultiLineString ();
     503               9 :         lineString = NULL;
     504                 : 
     505               9 :         poFeature->SetFID( nNextFID++ );
     506               9 :         poFeature->SetGeometryDirectly( multiLineString );
     507                 :     }
     508            1349 :     else if (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trk") == 0)
     509                 :     {
     510               6 :         trkFID++;
     511               6 :         trkSegId = 0;
     512                 :     }
     513            1343 :     else if (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkseg") == 0)
     514                 :     {
     515               6 :         trkSegId++;
     516               6 :         trkSegPtId = 0;
     517                 :     }
     518            1337 :     else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rte") == 0)
     519                 :     {
     520               6 :         interestingDepthLevel = depthLevel;
     521                 :         
     522               6 :         if (poFeature)
     523               0 :             delete poFeature;
     524                 : 
     525               6 :         poFeature = new OGRFeature( poFeatureDefn );
     526               6 :         inInterestingElement = TRUE;
     527               6 :         inExtensions = FALSE;
     528               6 :         inLink = FALSE;
     529               6 :         iCountLink = 0;
     530                 : 
     531              12 :         lineString = new OGRLineString ();
     532               6 :         poFeature->SetFID( nNextFID++ );
     533               6 :         poFeature->SetGeometryDirectly( lineString );
     534                 :     }
     535            1329 :     else if (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rte") == 0)
     536                 :     {
     537               4 :         rteFID++;
     538               4 :         rtePtId = 0;
     539                 :     }
     540            1321 :     else if (inInterestingElement)
     541                 :     {
     542             414 :         if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trkseg") == 0 &&
     543                 :             depthLevel == interestingDepthLevel + 1)
     544                 :         {
     545               9 :             if (multiLineString)
     546                 :             {
     547               9 :                 lineString = new OGRLineString ();
     548               9 :                 multiLineString->addGeometryDirectly( lineString );
     549                 :             }
     550                 :         }
     551             408 :         else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trkpt") == 0 &&
     552                 :                  depthLevel == interestingDepthLevel + 2)
     553                 :         {
     554              12 :             if (lineString)
     555                 :             {
     556              12 :                 hasFoundLat = FALSE;
     557              12 :                 hasFoundLon = FALSE;
     558              36 :                 for (i = 0; ppszAttr[i]; i += 2)
     559                 :                 {
     560              24 :                     if (strcmp(ppszAttr[i], "lat") == 0)
     561                 :                     {
     562              12 :                         hasFoundLat = TRUE;
     563              12 :                         latVal = CPLAtof(ppszAttr[i + 1]);
     564                 :                     }
     565              12 :                     else if (strcmp(ppszAttr[i], "lon") == 0)
     566                 :                     {
     567              12 :                         hasFoundLon = TRUE;
     568              12 :                         lonVal = CPLAtof(ppszAttr[i + 1]);
     569                 :                     }
     570                 :                 }
     571                 : 
     572              12 :                 if (hasFoundLat && hasFoundLon)
     573                 :                 {
     574              12 :                     lineString->addPoint(lonVal, latVal);
     575                 :                 }
     576                 :             }
     577                 :         }
     578             393 :         else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rtept") == 0 &&
     579                 :                  depthLevel == interestingDepthLevel + 1)
     580                 :         {
     581               9 :             if (lineString)
     582                 :             {
     583               9 :                 hasFoundLat = FALSE;
     584               9 :                 hasFoundLon = FALSE;
     585              27 :                 for (i = 0; ppszAttr[i]; i += 2)
     586                 :                 {
     587              18 :                     if (strcmp(ppszAttr[i], "lat") == 0)
     588                 :                     {
     589               9 :                         hasFoundLat = TRUE;
     590               9 :                         latVal = CPLAtof(ppszAttr[i + 1]);
     591                 :                     }
     592               9 :                     else if (strcmp(ppszAttr[i], "lon") == 0)
     593                 :                     {
     594               9 :                         hasFoundLon = TRUE;
     595               9 :                         lonVal = CPLAtof(ppszAttr[i + 1]);
     596                 :                     }
     597                 :                 }
     598                 : 
     599               9 :                 if (hasFoundLat && hasFoundLon)
     600                 :                 {
     601               9 :                     lineString->addPoint(lonVal, latVal);
     602                 :                 }
     603                 :             }
     604                 :         }
     605             375 :         else if (bEleAs25D &&
     606                 :                  strcmp(pszName, "ele") == 0 &&
     607                 :                  lineString != NULL &&
     608                 :                  ((gpxGeomType == GPX_ROUTE && depthLevel == interestingDepthLevel + 2) ||
     609                 :                   (gpxGeomType == GPX_TRACK && depthLevel == interestingDepthLevel + 3)))
     610                 :         {
     611               0 :             CPLFree(pszSubElementName);
     612               0 :             pszSubElementName = CPLStrdup(pszName);
     613                 :         }
     614             392 :         else if (depthLevel == interestingDepthLevel + 1 &&
     615                 :                  strcmp(pszName, "extensions") == 0)
     616                 :         {
     617              17 :             if (poDS->GetUseExtensions())
     618                 :             {
     619              17 :                 inExtensions = TRUE;
     620                 :             }
     621                 :         }
     622             590 :         else if (depthLevel == interestingDepthLevel + 1 ||
     623                 :                  (inExtensions && depthLevel == interestingDepthLevel + 2) )
     624                 :         {
     625             232 :             CPLFree(pszSubElementName);
     626             232 :             pszSubElementName = NULL;
     627             232 :             iCurrentField = -1;
     628                 :             
     629             232 :             if (strcmp(pszName, "link") == 0)
     630                 :             {
     631              53 :                 iCountLink++;
     632              53 :                 if (iCountLink <= nMaxLinks)
     633                 :                 {
     634              42 :                     if (ppszAttr[0] && ppszAttr[1] &&
     635                 :                         strcmp(ppszAttr[0], "href") == 0)
     636                 :                     {
     637                 :                         char szFieldName[32];
     638              42 :                         sprintf(szFieldName, "link%d_href", iCountLink);
     639              42 :                         iCurrentField = poFeatureDefn->GetFieldIndex(szFieldName);
     640              42 :                         poFeature->SetField( iCurrentField, ppszAttr[1]);
     641                 :                     }
     642                 :                 }
     643                 :                 else
     644                 :                 {
     645                 :                     static int once = 1;
     646              11 :                     if (once)
     647                 :                     {
     648               1 :                         once = 0;
     649                 :                         CPLError(CE_Warning, CPLE_AppDefined,
     650                 :                                  "GPX driver only reads %d links per element. Others will be ignored. "
     651                 :                                  "This can be changed with the GPX_N_MAX_LINKS environment variable",
     652               1 :                                  nMaxLinks);
     653                 :                     }
     654                 :                 }
     655              53 :                 inLink = TRUE;
     656              53 :                 iCurrentField = -1;
     657                 :             }
     658                 :             else
     659                 :             {
     660            1162 :                 for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     661                 :                 {
     662                 :                     int bMatch;
     663            1162 :                     if (iField >= nGPXFields)
     664                 :                     {
     665              36 :                         char* pszCompatibleName = OGRGPX_GetOGRCompatibleTagName(pszName);
     666                 :                         bMatch = (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
     667              36 :                                         pszCompatibleName ) == 0);
     668              36 :                         CPLFree(pszCompatibleName);
     669                 :                     }
     670                 :                     else
     671                 :                         bMatch = (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
     672            1126 :                                         pszName ) == 0);
     673                 :     
     674            1162 :                     if (bMatch)
     675                 :                     {
     676             179 :                         iCurrentField = iField;
     677             179 :                         pszSubElementName = CPLStrdup(pszName);
     678             179 :                         break;
     679                 :                     }
     680                 :                 }
     681                 :             }
     682                 :         }
     683             232 :         else if (depthLevel == interestingDepthLevel + 2 && inLink)
     684                 :         {
     685                 :             char szFieldName[32];
     686             106 :             CPLFree(pszSubElementName);
     687             106 :             pszSubElementName = NULL;
     688             106 :             iCurrentField = -1;
     689             106 :             if (iCountLink <= nMaxLinks)
     690                 :             {
     691              84 :                 if (strcmp(pszName, "type") == 0)
     692                 :                 {
     693              42 :                     sprintf(szFieldName, "link%d_type", iCountLink);
     694              42 :                     iCurrentField = poFeatureDefn->GetFieldIndex(szFieldName);
     695              42 :                     pszSubElementName = CPLStrdup(pszName);
     696                 :                 }
     697              42 :                 else if (strcmp(pszName, "text") == 0)
     698                 :                 {
     699              42 :                     sprintf(szFieldName, "link%d_text", iCountLink);
     700              42 :                     iCurrentField = poFeatureDefn->GetFieldIndex(szFieldName);
     701              42 :                     pszSubElementName = CPLStrdup(pszName);
     702                 :                 }
     703                 :             }
     704                 :         }
     705              20 :         else if (inExtensions && depthLevel > interestingDepthLevel + 2)
     706                 :         {
     707                 :             AddStrToSubElementValue(
     708               0 :                (ppszAttr[0] == NULL) ? CPLSPrintf("<%s>", pszName) :
     709               0 :                                     CPLSPrintf("<%s ", pszName));
     710                 :             int i;
     711               0 :             for (i = 0; ppszAttr[i]; i += 2)
     712                 :             {
     713                 :                 AddStrToSubElementValue(
     714               0 :                     CPLSPrintf("%s=\"%s\" ", ppszAttr[i], ppszAttr[i + 1]));
     715                 :             }
     716               0 :             if (ppszAttr[0] != NULL)
     717                 :             {
     718               0 :                 AddStrToSubElementValue(">");
     719                 :             }
     720                 :         }
     721                 :     }
     722                 : 
     723            1414 :     depthLevel++;
     724                 : }
     725                 : 
     726                 : /************************************************************************/
     727                 : /*                           endElementCbk()                            */
     728                 : /************************************************************************/
     729                 : 
     730            1414 : void OGRGPXLayer::endElementCbk(const char *pszName)
     731                 : {
     732            1414 :     if (bStopParsing) return;
     733                 : 
     734            1414 :     nWithoutEventCounter = 0;
     735                 : 
     736            1414 :     depthLevel--;
     737                 : 
     738            1414 :     if (inInterestingElement)
     739                 :     {
     740             544 :         if ((gpxGeomType == GPX_WPT && strcmp(pszName, "wpt") == 0) ||
     741                 :             (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rtept") == 0) ||
     742                 :             (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkpt") == 0))
     743                 :         {
     744              62 :             int bIsValid = (hasFoundLat && hasFoundLon);
     745              62 :             inInterestingElement = FALSE;
     746                 : 
     747              62 :             if( bIsValid
     748                 :                 &&  (m_poFilterGeom == NULL
     749                 :                     || FilterGeometry( poFeature->GetGeometryRef() ) )
     750                 :                 && (m_poAttrQuery == NULL
     751                 :                     || m_poAttrQuery->Evaluate( poFeature )) )
     752                 :             {
     753              62 :                 if( poFeature->GetGeometryRef() != NULL )
     754                 :                 {
     755              62 :                     poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
     756                 : 
     757              62 :                     if (bEleAs25D)
     758                 :                     {
     759               0 :                         for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     760                 :                         {
     761               0 :                             if (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), "ele" ) == 0)
     762                 :                             {
     763               0 :                                 if( poFeature->IsFieldSet( iField ) )
     764                 :                                 {
     765               0 :                                     double val =  poFeature->GetFieldAsDouble( iField);
     766               0 :                                     ((OGRPoint*)poFeature->GetGeometryRef())->setZ(val);
     767               0 :                                     poFeature->GetGeometryRef()->setCoordinateDimension(3);
     768                 :                                 }
     769               0 :                                 break;
     770                 :                             }
     771                 :                         }
     772                 :                     }
     773                 :                 }
     774                 : 
     775                 :                 ppoFeatureTab = (OGRFeature**)
     776                 :                         CPLRealloc(ppoFeatureTab,
     777              62 :                                     sizeof(OGRFeature*) * (nFeatureTabLength + 1));
     778              62 :                 ppoFeatureTab[nFeatureTabLength] = poFeature;
     779              62 :                 nFeatureTabLength++;
     780                 :             }
     781                 :             else
     782                 :             {
     783               0 :                 delete poFeature;
     784                 :             }
     785              62 :             poFeature = NULL;
     786                 :         }
     787             429 :         else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trk") == 0)
     788                 :         {
     789               9 :             inInterestingElement = FALSE;
     790               9 :             if( (m_poFilterGeom == NULL
     791                 :                     || FilterGeometry( poFeature->GetGeometryRef() ) )
     792                 :                 && (m_poAttrQuery == NULL
     793                 :                     || m_poAttrQuery->Evaluate( poFeature )) )
     794                 :             {
     795               9 :                 if( poFeature->GetGeometryRef() != NULL )
     796                 :                 {
     797               9 :                     poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
     798                 :                 }
     799                 : 
     800                 :                 ppoFeatureTab = (OGRFeature**)
     801                 :                         CPLRealloc(ppoFeatureTab,
     802               9 :                                     sizeof(OGRFeature*) * (nFeatureTabLength + 1));
     803               9 :                 ppoFeatureTab[nFeatureTabLength] = poFeature;
     804               9 :                 nFeatureTabLength++;
     805                 :             }
     806                 :             else
     807                 :             {
     808               0 :                 delete poFeature;
     809                 :             }
     810               9 :             poFeature = NULL;
     811               9 :             multiLineString = NULL;
     812               9 :             lineString = NULL;
     813                 :         }
     814             420 :         else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trkseg") == 0 &&
     815                 :                  depthLevel == interestingDepthLevel + 1)
     816                 :         {
     817               9 :             lineString = NULL;
     818                 :         }
     819             408 :         else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rte") == 0)
     820                 :         {
     821               6 :             inInterestingElement = FALSE;
     822               6 :             if( (m_poFilterGeom == NULL
     823                 :                     || FilterGeometry( poFeature->GetGeometryRef() ) )
     824                 :                 && (m_poAttrQuery == NULL
     825                 :                     || m_poAttrQuery->Evaluate( poFeature )) )
     826                 :             {
     827               6 :                 if( poFeature->GetGeometryRef() != NULL )
     828                 :                 {
     829               6 :                     poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
     830                 :                 }
     831                 : 
     832                 :                 ppoFeatureTab = (OGRFeature**)
     833                 :                         CPLRealloc(ppoFeatureTab,
     834               6 :                                     sizeof(OGRFeature*) * (nFeatureTabLength + 1));
     835               6 :                 ppoFeatureTab[nFeatureTabLength] = poFeature;
     836               6 :                 nFeatureTabLength++;
     837                 :             }
     838                 :             else
     839                 :             {
     840               0 :                 delete poFeature;
     841                 :             }
     842               6 :             poFeature = NULL;
     843               6 :             lineString = NULL;
     844                 :         }
     845             396 :         else if (bEleAs25D &&
     846                 :                  strcmp(pszName, "ele") == 0 &&
     847                 :                  lineString != NULL &&
     848                 :                  ((gpxGeomType == GPX_ROUTE && depthLevel == interestingDepthLevel + 2) ||
     849                 :                  (gpxGeomType == GPX_TRACK && depthLevel == interestingDepthLevel + 3)))
     850                 :         {
     851               0 :             poFeature->GetGeometryRef()->setCoordinateDimension(3);
     852                 : 
     853               0 :             if (nSubElementValueLen)
     854                 :             {
     855               0 :                 pszSubElementValue[nSubElementValueLen] = 0;
     856                 :     
     857               0 :                 double val = CPLAtof(pszSubElementValue);
     858               0 :                 int i = lineString->getNumPoints() - 1;
     859               0 :                 if (i >= 0)
     860               0 :                     lineString->setPoint(i, lineString->getX(i), lineString->getY(i), val);
     861                 :             }
     862                 : 
     863               0 :             CPLFree(pszSubElementName);
     864               0 :             pszSubElementName = NULL;
     865               0 :             CPLFree(pszSubElementValue);
     866               0 :             pszSubElementValue = NULL;
     867               0 :             nSubElementValueLen = 0;
     868                 :         }
     869             413 :         else if (depthLevel == interestingDepthLevel + 1 &&
     870                 :                  strcmp(pszName, "extensions") == 0)
     871                 :         {
     872              17 :             inExtensions = FALSE;
     873                 :         }
     874             558 :         else if ((depthLevel == interestingDepthLevel + 1 ||
     875                 :                  (inExtensions && depthLevel == interestingDepthLevel + 2) ) &&
     876                 :                  pszSubElementName && strcmp(pszName, pszSubElementName) == 0)
     877                 :         {
     878             179 :             if (poFeature && pszSubElementValue && nSubElementValueLen)
     879                 :             {
     880             176 :                 pszSubElementValue[nSubElementValueLen] = 0;
     881             176 :                 if (strcmp(pszSubElementName, "time") == 0)
     882                 :                 {
     883                 :                     int year, month, day, hour, minute, TZ;
     884                 :                     float second;
     885              23 :                     if (OGRParseXMLDateTime(pszSubElementValue, &year, &month, &day, &hour, &minute, &second, &TZ))
     886                 :                     {
     887              23 :                         poFeature->SetField(iCurrentField, year, month, day, hour, minute, (int)(second + .5), TZ);
     888                 :                     }
     889                 :                     else
     890                 :                     {
     891                 :                         CPLError(CE_Warning, CPLE_AppDefined,
     892               0 :                                  "Could not parse %s as a valid dateTime", pszSubElementValue);
     893                 :                     }
     894                 :                 }
     895                 :                 else
     896                 :                 {
     897             153 :                     poFeature->SetField( iCurrentField, pszSubElementValue);
     898                 :                 }
     899                 :             }
     900             179 :             if (strcmp(pszName, "link") == 0)
     901               0 :                 inLink = FALSE;
     902                 : 
     903             179 :             CPLFree(pszSubElementName);
     904             179 :             pszSubElementName = NULL;
     905             179 :             CPLFree(pszSubElementValue);
     906             179 :             pszSubElementValue = NULL;
     907             179 :             nSubElementValueLen = 0;
     908                 :         }
     909             306 :         else if (inLink && depthLevel == interestingDepthLevel + 2)
     910                 :         {
     911             106 :             if (iCurrentField != -1 && pszSubElementName &&
     912                 :                 strcmp(pszName, pszSubElementName) == 0 && poFeature && pszSubElementValue && nSubElementValueLen)
     913                 :             {
     914              84 :                 pszSubElementValue[nSubElementValueLen] = 0;
     915              84 :                 poFeature->SetField( iCurrentField, pszSubElementValue);
     916                 :             }
     917                 : 
     918             106 :             CPLFree(pszSubElementName);
     919             106 :             pszSubElementName = NULL;
     920             106 :             CPLFree(pszSubElementValue);
     921             106 :             pszSubElementValue = NULL;
     922             106 :             nSubElementValueLen = 0;
     923                 :         }
     924              94 :         else if (inExtensions && depthLevel > interestingDepthLevel + 2)
     925                 :         {
     926               0 :             AddStrToSubElementValue(CPLSPrintf("</%s>", pszName));
     927                 :         }
     928                 :     }
     929                 : }
     930                 : 
     931                 : /************************************************************************/
     932                 : /*                          dataHandlerCbk()                            */
     933                 : /************************************************************************/
     934                 : 
     935            3913 : void OGRGPXLayer::dataHandlerCbk(const char *data, int nLen)
     936                 : {
     937            3913 :     if (bStopParsing) return;
     938                 : 
     939            3913 :     nDataHandlerCounter ++;
     940            3913 :     if (nDataHandlerCounter >= BUFSIZ)
     941                 :     {
     942               0 :         CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
     943               0 :         XML_StopParser(oParser, XML_FALSE);
     944               0 :         bStopParsing = TRUE;
     945               0 :         return;
     946                 :     }
     947                 : 
     948            3913 :     nWithoutEventCounter = 0;
     949                 : 
     950            3913 :     if (pszSubElementName)
     951                 :     {
     952             260 :         if (inExtensions && depthLevel > interestingDepthLevel + 2)
     953                 :         {
     954              15 :             if (data[0] == '\n')
     955               0 :                 return;
     956                 :         }
     957             260 :         char* pszNewSubElementValue = (char*) VSIRealloc(pszSubElementValue, nSubElementValueLen + nLen + 1);
     958             260 :         if (pszNewSubElementValue == NULL)
     959                 :         {
     960               0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
     961               0 :             XML_StopParser(oParser, XML_FALSE);
     962               0 :             bStopParsing = TRUE;
     963               0 :             return;
     964                 :         }
     965             260 :         pszSubElementValue = pszNewSubElementValue;
     966             260 :         memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
     967             260 :         nSubElementValueLen += nLen;
     968             260 :         if (nSubElementValueLen > 100000)
     969                 :         {
     970                 :             CPLError(CE_Failure, CPLE_AppDefined,
     971               0 :                      "Too much data inside one element. File probably corrupted");
     972               0 :             XML_StopParser(oParser, XML_FALSE);
     973               0 :             bStopParsing = TRUE;
     974                 :         }
     975                 :     }
     976                 : }
     977                 : #endif
     978                 : 
     979                 : /************************************************************************/
     980                 : /*                           GetNextFeature()                           */
     981                 : /************************************************************************/
     982                 : 
     983              98 : OGRFeature *OGRGPXLayer::GetNextFeature()
     984                 : {
     985              98 :     if (bWriteMode)
     986                 :     {
     987                 :         CPLError(CE_Failure, CPLE_NotSupported,
     988               0 :                  "Cannot read features when writing a GPX file");
     989               0 :         return NULL;
     990                 :     }
     991                 : 
     992              98 :     if (fpGPX == NULL)
     993               0 :         return NULL;
     994                 : 
     995              98 :     if (bStopParsing)
     996               0 :         return NULL;
     997                 : 
     998                 : #ifdef HAVE_EXPAT
     999              98 :     if (nFeatureTabIndex < nFeatureTabLength)
    1000                 :     {
    1001              38 :         return ppoFeatureTab[nFeatureTabIndex++];
    1002                 :     }
    1003                 :     
    1004              60 :     if (VSIFEofL(fpGPX))
    1005              26 :         return NULL;
    1006                 :     
    1007                 :     char aBuf[BUFSIZ];
    1008                 :     
    1009              34 :     CPLFree(ppoFeatureTab);
    1010              34 :     ppoFeatureTab = NULL;
    1011              34 :     nFeatureTabLength = 0;
    1012              34 :     nFeatureTabIndex = 0;
    1013              34 :     nWithoutEventCounter = 0;
    1014                 : 
    1015                 :     int nDone;
    1016              34 :     do
    1017                 :     {
    1018              34 :         nDataHandlerCounter = 0;
    1019              34 :         unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGPX );
    1020              34 :         nDone = VSIFEofL(fpGPX);
    1021              34 :         if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
    1022                 :         {
    1023                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1024                 :                      "XML parsing of GPX file failed : %s at line %d, column %d",
    1025                 :                      XML_ErrorString(XML_GetErrorCode(oParser)),
    1026                 :                      (int)XML_GetCurrentLineNumber(oParser),
    1027               0 :                      (int)XML_GetCurrentColumnNumber(oParser));
    1028               0 :             bStopParsing = TRUE;
    1029               0 :             break;
    1030                 :         }
    1031              34 :         nWithoutEventCounter ++;
    1032                 :     } while (!nDone && nFeatureTabLength == 0 && !bStopParsing && nWithoutEventCounter < 10);
    1033                 : 
    1034              34 :     if (nWithoutEventCounter == 10)
    1035                 :     {
    1036                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1037               0 :                  "Too much data inside one element. File probably corrupted");
    1038               0 :         bStopParsing = TRUE;
    1039                 :     }
    1040                 : 
    1041              34 :     return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : NULL;
    1042                 : #else
    1043                 :     return NULL;
    1044                 : #endif
    1045                 : }
    1046                 : 
    1047                 : /************************************************************************/
    1048                 : /*                           GetSpatialRef()                            */
    1049                 : /************************************************************************/
    1050                 : 
    1051               0 : OGRSpatialReference *OGRGPXLayer::GetSpatialRef()
    1052                 : 
    1053                 : {
    1054               0 :     return poSRS;
    1055                 : }
    1056                 : 
    1057                 : /************************************************************************/
    1058                 : /*                  OGRGPX_GetXMLCompatibleTagName()                    */
    1059                 : /************************************************************************/
    1060                 : 
    1061               6 : static char* OGRGPX_GetXMLCompatibleTagName(const char* pszExtensionsNS,
    1062                 :                                             const char* pszName)
    1063                 : {
    1064                 :     /* Skip "ogr_" for example if NS is "ogr". Usefull for GPX -> GPX roundtrip */
    1065               6 :     if (strncmp(pszName, pszExtensionsNS, strlen(pszExtensionsNS)) == 0 &&
    1066               0 :         pszName[strlen(pszExtensionsNS)] == '_')
    1067                 :     {
    1068               0 :         pszName += strlen(pszExtensionsNS) + 1;
    1069                 :     }
    1070                 : 
    1071               6 :     char* pszModName = CPLStrdup(pszName);
    1072                 :     int i;
    1073              66 :     for(i=0;pszModName[i] != 0;i++)
    1074                 :     {
    1075              60 :         if (pszModName[i] == ' ')
    1076               6 :             pszModName[i] = '_';
    1077                 :     }
    1078               6 :     return pszModName;
    1079                 : }
    1080                 : 
    1081                 : /************************************************************************/
    1082                 : /*                     OGRGPX_GetUTF8String()                           */
    1083                 : /************************************************************************/
    1084                 : 
    1085               0 : static char* OGRGPX_GetUTF8String(const char* pszString)
    1086                 : {
    1087                 :     char *pszEscaped;
    1088               0 :     if (!CPLIsUTF8(pszString, -1) &&
    1089                 :          CSLTestBoolean(CPLGetConfigOption("OGR_FORCE_ASCII", "YES")))
    1090                 :     {
    1091                 :         static int bFirstTime = TRUE;
    1092               0 :         if (bFirstTime)
    1093                 :         {
    1094               0 :             bFirstTime = FALSE;
    1095                 :             CPLError(CE_Warning, CPLE_AppDefined,
    1096                 :                     "%s is not a valid UTF-8 string. Forcing it to ASCII.\n"
    1097                 :                     "If you still want the original string and change the XML file encoding\n"
    1098                 :                     "afterwards, you can define OGR_FORCE_ASCII=NO as configuration option.\n"
    1099               0 :                     "This warning won't be issued anymore", pszString);
    1100                 :         }
    1101                 :         else
    1102                 :         {
    1103                 :             CPLDebug("OGR", "%s is not a valid UTF-8 string. Forcing it to ASCII",
    1104               0 :                     pszString);
    1105                 :         }
    1106               0 :         pszEscaped = CPLForceToASCII(pszString, -1, '?');
    1107                 :     }
    1108                 :     else
    1109               0 :         pszEscaped = CPLStrdup(pszString);
    1110                 : 
    1111               0 :     return pszEscaped;
    1112                 : }
    1113                 : 
    1114                 : /************************************************************************/
    1115                 : /*                   OGRGPX_WriteXMLExtension()                          */
    1116                 : /************************************************************************/
    1117                 : 
    1118               0 : static int OGRGPX_WriteXMLExtension(FILE* fp,
    1119                 :                                     const char* pszTagName,
    1120                 :                                     const char* pszContent)
    1121                 : {
    1122               0 :     CPLXMLNode* poXML = CPLParseXMLString(pszContent);
    1123               0 :     if (poXML)
    1124                 :     {
    1125                 :         char* pszTagNameWithNS;
    1126               0 :         const char* pszXMLNS = NULL;
    1127               0 :         const char* pszUnderscore = strchr(pszTagName, '_');
    1128               0 :         pszTagNameWithNS = CPLStrdup(pszTagName);
    1129               0 :         if (pszUnderscore)
    1130               0 :             pszTagNameWithNS[pszUnderscore - pszTagName] = ':';
    1131                 : 
    1132                 :         /* If we detect a Garmin GPX extension, add its xmlns */
    1133               0 :         if (strcmp(pszTagName, "gpxx_WaypointExtension") == 0)
    1134               0 :             pszXMLNS = " xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\"";
    1135                 :             
    1136                 :         /* Don't XML escape here */
    1137               0 :         char *pszUTF8 = OGRGPX_GetUTF8String( pszContent );
    1138                 :         VSIFPrintf(fp, "    <%s%s>%s</%s>\n",
    1139               0 :                    pszTagNameWithNS, (pszXMLNS) ? pszXMLNS : "", pszUTF8, pszTagNameWithNS);
    1140               0 :         CPLFree(pszUTF8);
    1141                 :         
    1142               0 :         CPLFree(pszTagNameWithNS);
    1143               0 :         CPLDestroyXMLNode(poXML);
    1144                 :         
    1145               0 :         return TRUE;
    1146                 :     }
    1147                 :     
    1148               0 :     return FALSE;
    1149                 : }
    1150                 : 
    1151                 : /************************************************************************/
    1152                 : /*                      WriteFeatureAttributes()                        */
    1153                 : /************************************************************************/
    1154                 : 
    1155               9 : void OGRGPXLayer::WriteFeatureAttributes( OGRFeature *poFeature )
    1156                 : {
    1157               9 :     FILE* fp = poDS->GetOutputFP();
    1158                 :     int i;
    1159                 :     
    1160                 :     /* Begin with standard GPX fields */
    1161             161 :     for(i=0;i<nGPXFields;i++)
    1162                 :     { 
    1163             152 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
    1164             152 :         if( poFeature->IsFieldSet( i ) )
    1165                 :         {
    1166              17 :             const char* pszName = poFieldDefn->GetNameRef();
    1167              17 :             if (strcmp(pszName, "time") == 0)
    1168                 :             {
    1169                 :                 int year, month, day, hour, minute, second, TZFlag;
    1170               1 :                 if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
    1171                 :                                                   &hour, &minute, &second, &TZFlag))
    1172                 :                 {
    1173               1 :                     char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
    1174               1 :                     VSIFPrintf(fp, "  <time>%s</time>\n", pszDate);
    1175               1 :                     CPLFree(pszDate);
    1176                 :                 }
    1177                 :             }
    1178              16 :             else if (strncmp(pszName, "link", 4) == 0)
    1179                 :             {
    1180               6 :                 if (strstr(pszName, "href"))
    1181                 :                 {
    1182               2 :                     VSIFPrintf(fp, "  <link href=\"%s\">", poFeature->GetFieldAsString( i ));
    1183               2 :                     if( poFeature->IsFieldSet( i + 1 ) )
    1184               2 :                         VSIFPrintf(fp, "<text>%s</text>", poFeature->GetFieldAsString( i + 1 ));
    1185               2 :                     if( poFeature->IsFieldSet( i + 2 ) )
    1186               2 :                         VSIFPrintf(fp, "<type>%s</type>", poFeature->GetFieldAsString( i + 2 ));
    1187               2 :                     VSIFPrintf(fp, "</link>\n");
    1188                 :                 }
    1189                 :             }
    1190                 :             else
    1191                 :             {
    1192                 :                 char* pszValue =
    1193              10 :                         OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
    1194                 :                 VSIFPrintf(fp, "  <%s>%s</%s>\n",
    1195              10 :                         pszName, pszValue, pszName);
    1196              10 :                 CPLFree(pszValue);
    1197                 :             }
    1198                 :         }
    1199                 :     }
    1200                 : 
    1201                 :     /* Write "extra" fields within the <extensions> tag */
    1202               9 :     int n = poFeatureDefn->GetFieldCount();
    1203               9 :     if (i < n)
    1204                 :     {
    1205               2 :         const char* pszExtensionsNS = poDS->GetExtensionsNS();
    1206               2 :         VSIFPrintf(fp, "  <extensions>\n");
    1207               8 :         for(;i<n;i++)
    1208                 :         {
    1209               6 :             OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
    1210               6 :             if( poFeature->IsFieldSet( i ) )
    1211                 :             {
    1212                 :                 char* compatibleName =
    1213               6 :                         OGRGPX_GetXMLCompatibleTagName(pszExtensionsNS, poFieldDefn->GetNameRef());
    1214               6 :                 const char *pszRaw = poFeature->GetFieldAsString( i );
    1215                 :                 
    1216                 :                 /* Try to detect XML content */
    1217               6 :                 if (pszRaw[0] == '<' && pszRaw[strlen(pszRaw) - 1] == '>')
    1218                 :                 {
    1219               0 :                     if (OGRGPX_WriteXMLExtension(fp, compatibleName, pszRaw))
    1220               0 :                         continue;
    1221                 :                 }
    1222                 :                 
    1223                 :                 /* Try to detect XML escaped content */
    1224               6 :                 else if (strncmp(pszRaw, "&lt;", 4) == 0 &&
    1225                 :                          strncmp(pszRaw + strlen(pszRaw) - 4, "&gt;", 4) == 0)
    1226                 :                 {
    1227               0 :                     char* pszUnescapedContent = CPLUnescapeString( pszRaw, NULL, CPLES_XML );
    1228                 :                     
    1229               0 :                     if (OGRGPX_WriteXMLExtension(fp, compatibleName, pszUnescapedContent))
    1230                 :                     {
    1231               0 :                         CPLFree(pszUnescapedContent);
    1232               0 :                         continue;
    1233                 :                     }
    1234                 :                     
    1235               0 :                     CPLFree(pszUnescapedContent);
    1236                 :                 }
    1237                 : 
    1238                 :                 /* Remove leading spaces for a numeric field */
    1239               6 :                 if (poFieldDefn->GetType() == OFTInteger || poFieldDefn->GetType() == OFTReal)
    1240                 :                 {
    1241               0 :                     while( *pszRaw == ' ' )
    1242               0 :                         pszRaw++;
    1243                 :                 }
    1244                 : 
    1245               6 :                 char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
    1246                 :                 VSIFPrintf(fp, "    <%s:%s>%s</%s:%s>\n",
    1247                 :                         pszExtensionsNS,
    1248                 :                         compatibleName,
    1249                 :                         pszEscaped,
    1250                 :                         pszExtensionsNS,
    1251               6 :                         compatibleName);
    1252               6 :                 CPLFree(compatibleName);
    1253               6 :                 CPLFree(pszEscaped);
    1254                 :             }
    1255                 :         }
    1256               2 :         VSIFPrintf(fp, "  </extensions>\n");
    1257                 :     }
    1258               9 : }
    1259                 : 
    1260                 : /************************************************************************/
    1261                 : /*                CheckAndFixCoordinatesValidity()                      */
    1262                 : /************************************************************************/
    1263                 : 
    1264              11 : OGRErr OGRGPXLayer::CheckAndFixCoordinatesValidity( double* pdfLatitude, double* pdfLongitude )
    1265                 : {
    1266              11 :     if (pdfLatitude != NULL && (*pdfLatitude < -90 || *pdfLatitude > 90))
    1267                 :     {
    1268                 :         static int bFirstWarning = TRUE;
    1269               0 :         if (bFirstWarning)
    1270                 :         {
    1271                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1272                 :                      "Latitude %f is invalid. Valid range is [-90,90]. This warning will not be issued any more",
    1273               0 :                      *pdfLatitude);
    1274               0 :             bFirstWarning = FALSE;
    1275                 :         }
    1276               0 :         return CE_Failure;
    1277                 :     }
    1278                 : 
    1279              11 :     if (pdfLongitude != NULL && (*pdfLongitude < -180 || *pdfLongitude > 180))
    1280                 :     {
    1281                 :         static int bFirstWarning = TRUE;
    1282               0 :         if (bFirstWarning)
    1283                 :         {
    1284                 :             CPLError(CE_Warning, CPLE_AppDefined,
    1285                 :                      "Longitude %f has been modified to fit into range [-180,180]. This warning will not be issued any more",
    1286               0 :                      *pdfLongitude);
    1287               0 :             bFirstWarning = FALSE;
    1288                 :         }
    1289                 : 
    1290               0 :         if (*pdfLongitude > 180)
    1291               0 :             *pdfLongitude -= ((int) ((*pdfLongitude+180)/360)*360);
    1292               0 :         else if (*pdfLongitude < -180)
    1293               0 :             *pdfLongitude += ((int) (180 - *pdfLongitude)/360)*360;
    1294                 : 
    1295               0 :         return CE_None;
    1296                 :     }
    1297                 : 
    1298              11 :     return CE_None;
    1299                 : }
    1300                 : 
    1301                 : /************************************************************************/
    1302                 : /*                           CreateFeature()                            */
    1303                 : /************************************************************************/
    1304                 : 
    1305               9 : OGRErr OGRGPXLayer::CreateFeature( OGRFeature *poFeature )
    1306                 : 
    1307                 : {
    1308               9 :     FILE* fp = poDS->GetOutputFP();
    1309               9 :     if (fp == NULL)
    1310               0 :         return CE_Failure;
    1311                 :     
    1312               9 :     OGRGeometry     *poGeom = poFeature->GetGeometryRef();
    1313                 :     
    1314               9 :     if (gpxGeomType == GPX_WPT)
    1315                 :     {
    1316               4 :         if (poDS->GetLastGPXGeomTypeWritten() == GPX_ROUTE)
    1317                 :         {
    1318                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1319               0 :                         "Cannot write a 'wpt' element after a 'rte' element.\n");
    1320               0 :             return OGRERR_FAILURE;
    1321                 :         }
    1322                 :         else
    1323               4 :         if (poDS->GetLastGPXGeomTypeWritten() == GPX_TRACK)
    1324                 :         {
    1325                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1326               0 :                         "Cannot write a 'wpt' element after a 'trk' element.\n");
    1327               0 :             return OGRERR_FAILURE;
    1328                 :         }
    1329                 :         
    1330               4 :         poDS->SetLastGPXGeomTypeWritten(gpxGeomType);
    1331                 : 
    1332               4 :         if ( poGeom == NULL )
    1333                 :         {
    1334                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1335               0 :                       "Features without geometry not supported by GPX writer in waypoints layer." );
    1336               0 :             return OGRERR_FAILURE;
    1337                 :         }
    1338                 : 
    1339               4 :         switch( poGeom->getGeometryType() )
    1340                 :         {
    1341                 :             case wkbPoint:
    1342                 :             case wkbPoint25D:
    1343                 :             {
    1344               4 :                 OGRPoint* point = (OGRPoint*)poGeom;
    1345               4 :                 double lat = point->getY();
    1346               4 :                 double lon = point->getX();
    1347               4 :                 CheckAndFixCoordinatesValidity(&lat, &lon);
    1348               4 :                 poDS->AddCoord(lon, lat);
    1349               4 :                 VSIFPrintf(fp, "<wpt lat=\"%.15f\" lon=\"%.15f\">\n", lat, lon);
    1350               4 :                 WriteFeatureAttributes(poFeature);
    1351               4 :                 VSIFPrintf(fp, "</wpt>\n");
    1352                 :                 break;
    1353                 :             }
    1354                 :             
    1355                 :             default:
    1356                 :             {
    1357                 :                 CPLError( CE_Failure, CPLE_NotSupported,
    1358                 :                     "Geometry type of `%s' not supported fort 'wpt' element.\n",
    1359               0 :                     OGRGeometryTypeToName(poGeom->getGeometryType()) );
    1360               0 :                 return OGRERR_FAILURE;
    1361                 :             }
    1362                 :         }
    1363                 :     }
    1364               5 :     else if (gpxGeomType == GPX_ROUTE)
    1365                 :     {
    1366               2 :         if (poDS->GetLastGPXGeomTypeWritten() == GPX_TRACK)
    1367                 :         {
    1368                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1369               0 :                         "Cannot write a 'rte' element after a 'trk' element.\n");
    1370               0 :             return OGRERR_FAILURE;
    1371                 :         }
    1372                 :         
    1373               2 :         poDS->SetLastGPXGeomTypeWritten(gpxGeomType);
    1374                 : 
    1375               2 :         OGRLineString* line = NULL;
    1376                 : 
    1377               2 :         if ( poGeom == NULL )
    1378                 :         {
    1379               0 :             VSIFPrintf(fp, "<rte>\n");
    1380               0 :             WriteFeatureAttributes(poFeature);
    1381               0 :             VSIFPrintf(fp, "</rte>\n");
    1382               0 :             return OGRERR_NONE;
    1383                 :         }
    1384                 : 
    1385               2 :         switch( poGeom->getGeometryType() )
    1386                 :         {
    1387                 :             case wkbLineString:
    1388                 :             case wkbLineString25D:
    1389                 :             {
    1390               2 :                 line = (OGRLineString*)poGeom;
    1391               2 :                 break;
    1392                 :             }
    1393                 : 
    1394                 :             case wkbMultiLineString:
    1395                 :             case wkbMultiLineString25D:
    1396                 :             {
    1397               0 :                 int nGeometries = ((OGRGeometryCollection*)poGeom)->getNumGeometries ();
    1398               0 :                 if (nGeometries == 0)
    1399                 :                 {
    1400               0 :                     line = NULL;
    1401                 :                 }
    1402               0 :                 else if (nGeometries == 1)
    1403                 :                 {
    1404               0 :                     line = (OGRLineString*) ( ((OGRGeometryCollection*)poGeom)->getGeometryRef(0) );
    1405                 :                 }
    1406                 :                 else
    1407                 :                 {
    1408                 :                     CPLError( CE_Failure, CPLE_NotSupported,
    1409               0 :                             "Multiline with more than one line is not supported for 'rte' element.\n");
    1410               0 :                     return OGRERR_FAILURE;
    1411                 :                 }
    1412               0 :                 break;
    1413                 :             }
    1414                 : 
    1415                 :             default:
    1416                 :             {
    1417                 :                 CPLError( CE_Failure, CPLE_NotSupported,
    1418                 :                             "Geometry type of `%s' not supported for 'rte' element.\n",
    1419               0 :                             OGRGeometryTypeToName(poGeom->getGeometryType()) );
    1420               0 :                 return OGRERR_FAILURE;
    1421                 :             }
    1422                 :         }
    1423                 : 
    1424               2 :         int n = (line) ? line->getNumPoints() : 0;
    1425                 :         int i;
    1426               2 :         VSIFPrintf(fp, "<rte>\n");
    1427               2 :         WriteFeatureAttributes(poFeature);
    1428               5 :         for(i=0;i<n;i++)
    1429                 :         {
    1430               3 :             double lat = line->getY(i);
    1431               3 :             double lon = line->getX(i);
    1432               3 :             CheckAndFixCoordinatesValidity(&lat, &lon);
    1433               3 :             poDS->AddCoord(lon, lat);
    1434               3 :             VSIFPrintf(fp, "  <rtept lat=\"%.15f\" lon=\"%.15f\">\n", lat, lon);
    1435               6 :             if (poGeom->getGeometryType() == wkbLineString25D ||
    1436               3 :                 poGeom->getGeometryType() == wkbMultiLineString25D)
    1437                 :             {
    1438               0 :                 VSIFPrintf(fp, "    <ele>%f</ele>\n", line->getZ(i));
    1439                 :             }
    1440               3 :             VSIFPrintf(fp, "  </rtept>\n");
    1441                 :         }
    1442               2 :         VSIFPrintf(fp, "</rte>\n");
    1443                 :     }
    1444                 :     else
    1445                 :     {
    1446               3 :         poDS->SetLastGPXGeomTypeWritten(gpxGeomType);
    1447                 : 
    1448               3 :         if (poGeom == NULL)
    1449                 :         {
    1450               0 :             VSIFPrintf(fp, "<trk>\n");
    1451               0 :             WriteFeatureAttributes(poFeature);
    1452               0 :             VSIFPrintf(fp, "</trk>\n");
    1453               0 :             return OGRERR_NONE;
    1454                 :         }
    1455                 : 
    1456               3 :         switch( poGeom->getGeometryType() )
    1457                 :         {
    1458                 :             case wkbLineString:
    1459                 :             case wkbLineString25D:
    1460                 :             {
    1461               0 :                 OGRLineString* line = (OGRLineString*)poGeom;
    1462               0 :                 int n = line->getNumPoints();
    1463                 :                 int i;
    1464               0 :                 VSIFPrintf(fp, "<trk>\n");
    1465               0 :                 WriteFeatureAttributes(poFeature);
    1466               0 :                 VSIFPrintf(fp, "  <trkseg>\n");
    1467               0 :                 for(i=0;i<n;i++)
    1468                 :                 {
    1469               0 :                     double lat = line->getY(i);
    1470               0 :                     double lon = line->getX(i);
    1471               0 :                     CheckAndFixCoordinatesValidity(&lat, &lon);
    1472               0 :                     poDS->AddCoord(lon, lat);
    1473               0 :                     VSIFPrintf(fp, "    <trkpt lat=\"%.15f\" lon=\"%.15f\">\n", lat, lon);
    1474               0 :                     if (line->getGeometryType() == wkbLineString25D)
    1475                 :                     {
    1476               0 :                         VSIFPrintf(fp, "        <ele>%f</ele>\n", line->getZ(i));
    1477                 :                     }
    1478               0 :                     VSIFPrintf(fp, "    </trkpt>\n");
    1479                 :                 }
    1480               0 :                 VSIFPrintf(fp, "  </trkseg>\n");
    1481               0 :                 VSIFPrintf(fp, "</trk>\n");
    1482               0 :                 break;
    1483                 :             }
    1484                 : 
    1485                 :             case wkbMultiLineString:
    1486                 :             case wkbMultiLineString25D:
    1487                 :             {
    1488               3 :                 int nGeometries = ((OGRGeometryCollection*)poGeom)->getNumGeometries ();
    1489               3 :                 VSIFPrintf(fp, "<trk>\n");
    1490               3 :                 WriteFeatureAttributes(poFeature);
    1491                 :                 int j;
    1492               6 :                 for(j=0;j<nGeometries;j++)
    1493                 :                 {
    1494               3 :                     OGRLineString* line = (OGRLineString*) ( ((OGRGeometryCollection*)poGeom)->getGeometryRef(j) );
    1495               3 :                     int n = (line) ? line->getNumPoints() : 0;
    1496                 :                     int i;
    1497               3 :                     VSIFPrintf(fp, "  <trkseg>\n");
    1498               7 :                     for(i=0;i<n;i++)
    1499                 :                     {
    1500               4 :                         double lat = line->getY(i);
    1501               4 :                         double lon = line->getX(i);
    1502               4 :                         CheckAndFixCoordinatesValidity(&lat, &lon);
    1503               4 :                         poDS->AddCoord(lon, lat);
    1504               4 :                         VSIFPrintf(fp, "    <trkpt lat=\"%.15f\" lon=\"%.15f\">\n", lat, lon);
    1505               4 :                         if (line->getGeometryType() == wkbLineString25D)
    1506                 :                         {
    1507               0 :                             VSIFPrintf(fp, "        <ele>%f</ele>\n", line->getZ(i));
    1508                 :                         }
    1509               4 :                         VSIFPrintf(fp, "    </trkpt>\n");
    1510                 :                     }
    1511               3 :                     VSIFPrintf(fp, "  </trkseg>\n");
    1512                 :                 }
    1513               3 :                 VSIFPrintf(fp, "</trk>\n");
    1514               3 :                 break;
    1515                 :             }
    1516                 : 
    1517                 :             default:
    1518                 :             {
    1519                 :                 CPLError( CE_Failure, CPLE_NotSupported,
    1520                 :                             "Geometry type of `%s' not supported for 'trk' element.\n",
    1521               0 :                             OGRGeometryTypeToName(poGeom->getGeometryType()) );
    1522               0 :                 return OGRERR_FAILURE;
    1523                 :             }
    1524                 :         }
    1525                 :     }
    1526                 : 
    1527               9 :     return OGRERR_NONE;
    1528                 : }
    1529                 : 
    1530                 : 
    1531                 : 
    1532                 : /************************************************************************/
    1533                 : /*                            CreateField()                             */
    1534                 : /************************************************************************/
    1535                 : 
    1536                 : 
    1537               3 : OGRErr OGRGPXLayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
    1538                 : 
    1539                 : {
    1540              75 :     for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
    1541                 :     {
    1542              72 :         if (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    1543                 :                    poField->GetNameRef() ) == 0)
    1544                 :         {
    1545               0 :             return OGRERR_NONE;
    1546                 :         }
    1547                 :     }
    1548               3 :     if (poDS->GetUseExtensions() == FALSE)
    1549                 :     {
    1550                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1551                 :                 "Field of name '%s' is not supported in GPX schema. "
    1552                 :                  "Use GPX_USE_EXTENSIONS creation option to allow use of the <extensions> element.",
    1553               0 :                  poField->GetNameRef());
    1554               0 :         return OGRERR_FAILURE;
    1555                 :     }
    1556                 :     else
    1557                 :     {
    1558               3 :         poFeatureDefn->AddFieldDefn( poField );
    1559               3 :         return OGRERR_NONE;
    1560                 :     }
    1561                 : }
    1562                 : 
    1563                 : /************************************************************************/
    1564                 : /*                           TestCapability()                           */
    1565                 : /************************************************************************/
    1566                 : 
    1567               0 : int OGRGPXLayer::TestCapability( const char * pszCap )
    1568                 : 
    1569                 : {
    1570               0 :     if( EQUAL(pszCap,OLCSequentialWrite) )
    1571               0 :         return bWriteMode;
    1572                 : 
    1573               0 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
    1574               0 :         return TRUE;
    1575                 : 
    1576                 :     else
    1577               0 :         return FALSE;
    1578                 : }
    1579                 : 
    1580                 : 
    1581                 : /************************************************************************/
    1582                 : /*                       LoadExtensionsSchema()                         */
    1583                 : /************************************************************************/
    1584                 : 
    1585                 : #ifdef HAVE_EXPAT
    1586                 : 
    1587             310 : static void XMLCALL startElementLoadSchemaCbk(void *pUserData, const char *pszName, const char **ppszAttr)
    1588                 : {
    1589             310 :     ((OGRGPXLayer*)pUserData)->startElementLoadSchemaCbk(pszName, ppszAttr);
    1590             310 : }
    1591                 : 
    1592             310 : static void XMLCALL endElementLoadSchemaCbk(void *pUserData, const char *pszName)
    1593                 : {
    1594             310 :     ((OGRGPXLayer*)pUserData)->endElementLoadSchemaCbk(pszName);
    1595             310 : }
    1596                 : 
    1597             855 : static void XMLCALL dataHandlerLoadSchemaCbk(void *pUserData, const char *data, int nLen)
    1598                 : {
    1599             855 :     ((OGRGPXLayer*)pUserData)->dataHandlerLoadSchemaCbk(data, nLen);
    1600             855 : }
    1601                 : 
    1602                 : 
    1603                 : /** This function parses the whole file to detect the extensions fields */
    1604              10 : void OGRGPXLayer::LoadExtensionsSchema()
    1605                 : {
    1606              10 :     oSchemaParser = OGRCreateExpatXMLParser();
    1607              10 :     XML_SetElementHandler(oSchemaParser, ::startElementLoadSchemaCbk, ::endElementLoadSchemaCbk);
    1608              10 :     XML_SetCharacterDataHandler(oSchemaParser, ::dataHandlerLoadSchemaCbk);
    1609              10 :     XML_SetUserData(oSchemaParser, this);
    1610                 : 
    1611              10 :     VSIFSeekL( fpGPX, 0, SEEK_SET );
    1612                 : 
    1613              10 :     inInterestingElement = FALSE;
    1614              10 :     inExtensions = FALSE;
    1615              10 :     depthLevel = 0;
    1616              10 :     currentFieldDefn = NULL;
    1617              10 :     pszSubElementName = NULL;
    1618              10 :     pszSubElementValue = NULL;
    1619              10 :     nSubElementValueLen = 0;
    1620              10 :     nWithoutEventCounter = 0;
    1621              10 :     bStopParsing = FALSE;
    1622                 : 
    1623                 :     char aBuf[BUFSIZ];
    1624                 :     int nDone;
    1625              10 :     do
    1626                 :     {
    1627              10 :         nDataHandlerCounter = 0;
    1628              10 :         unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGPX );
    1629              10 :         nDone = VSIFEofL(fpGPX);
    1630              10 :         if (XML_Parse(oSchemaParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
    1631                 :         {
    1632                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1633                 :                      "XML parsing of GPX file failed : %s at line %d, column %d",
    1634                 :                      XML_ErrorString(XML_GetErrorCode(oSchemaParser)),
    1635                 :                      (int)XML_GetCurrentLineNumber(oSchemaParser),
    1636               0 :                      (int)XML_GetCurrentColumnNumber(oSchemaParser));
    1637               0 :             bStopParsing = TRUE;
    1638               0 :             break;
    1639                 :         }
    1640              10 :         nWithoutEventCounter ++;
    1641                 :     } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
    1642                 : 
    1643              10 :     if (nWithoutEventCounter == 10)
    1644                 :     {
    1645                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1646               0 :                  "Too much data inside one element. File probably corrupted");
    1647               0 :         bStopParsing = TRUE;
    1648                 :     }
    1649                 : 
    1650              10 :     XML_ParserFree(oSchemaParser);
    1651              10 :     oSchemaParser = NULL;
    1652                 : 
    1653              10 :     VSIFSeekL( fpGPX, 0, SEEK_SET );
    1654              10 : }
    1655                 : 
    1656                 : 
    1657                 : /************************************************************************/
    1658                 : /*                  startElementLoadSchemaCbk()                         */
    1659                 : /************************************************************************/
    1660                 : 
    1661                 : 
    1662             310 : void OGRGPXLayer::startElementLoadSchemaCbk(const char *pszName, const char **ppszAttr)
    1663                 : {
    1664             310 :     if (bStopParsing) return;
    1665                 : 
    1666             310 :     nWithoutEventCounter = 0;
    1667                 : 
    1668             314 :     if (gpxGeomType == GPX_WPT && strcmp(pszName, "wpt") == 0)
    1669                 :     {
    1670               4 :         inInterestingElement = TRUE;
    1671               4 :         inExtensions = FALSE;
    1672               4 :         interestingDepthLevel = depthLevel;
    1673                 :     }
    1674             309 :     else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trk") == 0)
    1675                 :     {
    1676               3 :         inInterestingElement = TRUE;
    1677               3 :         inExtensions = FALSE;
    1678               3 :         interestingDepthLevel = depthLevel;
    1679                 :     }
    1680             305 :     else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rte") == 0)
    1681                 :     {
    1682               2 :         inInterestingElement = TRUE;
    1683               2 :         inExtensions = FALSE;
    1684               2 :         interestingDepthLevel = depthLevel;
    1685                 :     }
    1686             305 :     else if (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkpt") == 0)
    1687                 :     {
    1688               4 :         inInterestingElement = TRUE;
    1689               4 :         inExtensions = FALSE;
    1690               4 :         interestingDepthLevel = depthLevel;
    1691                 :     }
    1692             300 :     else if (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rtept") == 0)
    1693                 :     {
    1694               3 :         inInterestingElement = TRUE;
    1695               3 :         inExtensions = FALSE;
    1696               3 :         interestingDepthLevel = depthLevel;
    1697                 :     }
    1698             294 :     else if (inInterestingElement)
    1699                 :     {
    1700              62 :         if (depthLevel == interestingDepthLevel + 1 &&
    1701                 :             strcmp(pszName, "extensions") == 0)
    1702                 :         {
    1703               3 :             inExtensions = TRUE;
    1704               3 :             extensionsDepthLevel = depthLevel;
    1705                 :         }
    1706              56 :         else if (inExtensions && depthLevel == extensionsDepthLevel + 1)
    1707                 :         {
    1708               6 :             CPLFree(pszSubElementName);
    1709               6 :             pszSubElementName = CPLStrdup(pszName);
    1710                 : 
    1711                 :             int iField;
    1712             150 :             for(iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
    1713                 :             {
    1714                 :                 int bMatch;
    1715             147 :                 if (iField >= nGPXFields)
    1716                 :                 {
    1717               9 :                     char* pszCompatibleName = OGRGPX_GetOGRCompatibleTagName(pszName);
    1718               9 :                     bMatch = (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), pszCompatibleName ) == 0);
    1719               9 :                     CPLFree(pszCompatibleName);
    1720                 :                 }
    1721                 :                 else
    1722             138 :                     bMatch = (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), pszName ) == 0);
    1723                 :                 
    1724             147 :                 if (bMatch)
    1725                 :                 {
    1726               3 :                     currentFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    1727               3 :                     break;
    1728                 :                 }
    1729                 :             }
    1730               6 :             if (iField == poFeatureDefn->GetFieldCount())
    1731                 :             {
    1732               3 :                 char* pszCompatibleName = OGRGPX_GetOGRCompatibleTagName(pszName);
    1733               3 :                 OGRFieldDefn newFieldDefn(pszCompatibleName, OFTInteger);
    1734               3 :                 CPLFree(pszCompatibleName);
    1735                 :                 
    1736               3 :                 poFeatureDefn->AddFieldDefn(&newFieldDefn);
    1737               3 :                 currentFieldDefn = poFeatureDefn->GetFieldDefn(poFeatureDefn->GetFieldCount() - 1);
    1738                 : 
    1739               3 :                 if (poFeatureDefn->GetFieldCount() == 100)
    1740                 :                 {
    1741                 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1742               0 :                             "Too many fields. File probably corrupted");
    1743               0 :                     XML_StopParser(oSchemaParser, XML_FALSE);
    1744               0 :                     bStopParsing = TRUE;
    1745               3 :                 }
    1746                 :             }
    1747                 :         }
    1748                 :     }
    1749                 : 
    1750             310 :     depthLevel++;
    1751                 : }
    1752                 : 
    1753                 : 
    1754                 : /************************************************************************/
    1755                 : /*                   endElementLoadSchemaCbk()                           */
    1756                 : /************************************************************************/
    1757                 : 
    1758               0 : static int OGRGPXIsInt(const char* pszStr)
    1759                 : {
    1760                 :     int i;
    1761                 : 
    1762               0 :     while(*pszStr == ' ')
    1763               0 :         pszStr++;
    1764                 : 
    1765               0 :     for(i=0;pszStr[i];i++)
    1766                 :     {
    1767               0 :         if (pszStr[i] == '+' || pszStr[i] == '-')
    1768                 :         {
    1769               0 :             if (i != 0)
    1770               0 :                 return FALSE;
    1771                 :         }
    1772               0 :         else if (!(pszStr[i] >= '0' && pszStr[i] <= '9'))
    1773               0 :             return FALSE;
    1774                 :     }
    1775               0 :     return TRUE;
    1776                 : }
    1777                 : 
    1778                 : 
    1779             310 : void OGRGPXLayer::endElementLoadSchemaCbk(const char *pszName)
    1780                 : {
    1781             310 :     if (bStopParsing) return;
    1782                 : 
    1783             310 :     nWithoutEventCounter = 0;
    1784                 : 
    1785             310 :     depthLevel--;
    1786                 : 
    1787             310 :     if (inInterestingElement)
    1788                 :     {
    1789              79 :         if (gpxGeomType == GPX_WPT && strcmp(pszName, "wpt") == 0)
    1790                 :         {
    1791               4 :             inInterestingElement = FALSE;
    1792               4 :             inExtensions = FALSE;
    1793                 :         }
    1794              74 :         else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trk") == 0)
    1795                 :         {
    1796               3 :             inInterestingElement = FALSE;
    1797               3 :             inExtensions = FALSE;
    1798                 :         }
    1799              70 :         else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rte") == 0)
    1800                 :         {
    1801               2 :             inInterestingElement = FALSE;
    1802               2 :             inExtensions = FALSE;
    1803                 :         }
    1804              70 :         else if (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkpt") == 0)
    1805                 :         {
    1806               4 :             inInterestingElement = FALSE;
    1807               4 :             inExtensions = FALSE;
    1808                 :         }
    1809              65 :         else if (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rtept") == 0)
    1810                 :         {
    1811               3 :             inInterestingElement = FALSE;
    1812               3 :             inExtensions = FALSE;
    1813                 :         }
    1814              62 :         else if (depthLevel == interestingDepthLevel + 1 &&
    1815                 :                  strcmp(pszName, "extensions") == 0)
    1816                 :         {
    1817               3 :             inExtensions = FALSE;
    1818                 :         }
    1819              56 :         else if (inExtensions && depthLevel == extensionsDepthLevel + 1 &&
    1820                 :                  pszSubElementName && strcmp(pszName, pszSubElementName) == 0)
    1821                 :         {
    1822               6 :             if (pszSubElementValue && nSubElementValueLen && currentFieldDefn)
    1823                 :             {
    1824               5 :                 pszSubElementValue[nSubElementValueLen] = 0;
    1825               5 :                 if (currentFieldDefn->GetType() == OFTInteger ||
    1826                 :                     currentFieldDefn->GetType() == OFTReal)
    1827                 :                 {
    1828               3 :                     char* pszRemainingStr = NULL;
    1829               3 :                     CPLStrtod(pszSubElementValue, &pszRemainingStr);
    1830               3 :                     if (pszRemainingStr == NULL ||
    1831                 :                         *pszRemainingStr == 0 ||
    1832                 :                         *pszRemainingStr == ' ')
    1833                 :                     {
    1834               0 :                         if (currentFieldDefn->GetType() == OFTInteger)
    1835                 :                         {
    1836               0 :                             if (OGRGPXIsInt(pszSubElementValue) == FALSE)
    1837                 :                             {
    1838               0 :                                 currentFieldDefn->SetType(OFTReal);
    1839                 :                             }
    1840                 :                         }
    1841                 :                     }
    1842                 :                     else
    1843                 :                     {
    1844               3 :                         currentFieldDefn->SetType(OFTString);
    1845                 :                     }
    1846                 :                 }
    1847                 :             }
    1848                 : 
    1849               6 :             CPLFree(pszSubElementName);
    1850               6 :             pszSubElementName = NULL;
    1851               6 :             CPLFree(pszSubElementValue);
    1852               6 :             pszSubElementValue = NULL;
    1853               6 :             nSubElementValueLen = 0;
    1854               6 :             currentFieldDefn = NULL;
    1855                 :         }
    1856                 :     }
    1857                 : }
    1858                 : 
    1859                 : /************************************************************************/
    1860                 : /*                   dataHandlerLoadSchemaCbk()                         */
    1861                 : /************************************************************************/
    1862                 : 
    1863             855 : void OGRGPXLayer::dataHandlerLoadSchemaCbk(const char *data, int nLen)
    1864                 : {
    1865             855 :     if (bStopParsing) return;
    1866                 : 
    1867             855 :     nDataHandlerCounter ++;
    1868             855 :     if (nDataHandlerCounter >= BUFSIZ)
    1869                 :     {
    1870               0 :         CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
    1871               0 :         XML_StopParser(oSchemaParser, XML_FALSE);
    1872               0 :         bStopParsing = TRUE;
    1873               0 :         return;
    1874                 :     }
    1875                 : 
    1876             855 :     nWithoutEventCounter = 0;
    1877                 : 
    1878             855 :     if (pszSubElementName)
    1879                 :     {
    1880               5 :         char* pszNewSubElementValue = (char*) VSIRealloc(pszSubElementValue, nSubElementValueLen + nLen + 1);
    1881               5 :         if (pszNewSubElementValue == NULL)
    1882                 :         {
    1883               0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    1884               0 :             XML_StopParser(oSchemaParser, XML_FALSE);
    1885               0 :             bStopParsing = TRUE;
    1886               0 :             return;
    1887                 :         }
    1888               5 :         pszSubElementValue = pszNewSubElementValue;
    1889               5 :         memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
    1890               5 :         nSubElementValueLen += nLen;
    1891               5 :         if (nSubElementValueLen > 100000)
    1892                 :         {
    1893                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1894               0 :                      "Too much data inside one element. File probably corrupted");
    1895               0 :             XML_StopParser(oSchemaParser, XML_FALSE);
    1896               0 :             bStopParsing = TRUE;
    1897                 :         }
    1898                 :     }
    1899                 : }
    1900                 : #else
    1901                 : void OGRGPXLayer::LoadExtensionsSchema()
    1902                 : {
    1903                 : }
    1904                 : #endif

Generated by: LCOV version 1.7