LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gpx - ogrgpxlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1031 767 74.4 %
Date: 2011-12-18 Functions: 33 24 72.7 %

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

Generated by: LCOV version 1.7