LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gpx - ogrgpxdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 230 191 83.0 %
Date: 2011-12-18 Functions: 16 12 75.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgpxdatasource.cpp 23557 2011-12-12 22:08:17Z rouault $
       3                 :  *
       4                 :  * Project:  GPX Translator
       5                 :  * Purpose:  Implements OGRGPXDataSource 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_csv.h"
      34                 : 
      35                 : CPL_CVSID("$Id: ogrgpxdatasource.cpp 23557 2011-12-12 22:08:17Z rouault $");
      36                 : 
      37                 : #define SPACE_FOR_METADATA 160
      38                 : 
      39                 : /************************************************************************/
      40                 : /*                          OGRGPXDataSource()                          */
      41                 : /************************************************************************/
      42                 : 
      43             237 : OGRGPXDataSource::OGRGPXDataSource()
      44                 : 
      45                 : {
      46             237 :     lastGPXGeomTypeWritten = GPX_NONE;
      47             237 :     bUseExtensions = FALSE;
      48             237 :     pszExtensionsNS = NULL;
      49                 : 
      50             237 :     papoLayers = NULL;
      51             237 :     nLayers = 0;
      52                 :     
      53             237 :     fpOutput = NULL;
      54             237 :     nOffsetBounds = -1;
      55             237 :     dfMinLat = 90;
      56             237 :     dfMinLon = 180;
      57             237 :     dfMaxLat = -90;
      58             237 :     dfMaxLon = -180;
      59                 : 
      60             237 :     pszName = NULL;
      61             237 :     pszVersion = NULL;
      62                 : 
      63             237 :     bIsBackSeekable = TRUE;
      64             237 :     pszEOL = "\n";
      65                 : 
      66             237 :     nLastRteId = -1;
      67             237 :     nLastTrkId = -1;
      68             237 :     nLastTrkSegId = -1;
      69             237 : }
      70                 : 
      71                 : /************************************************************************/
      72                 : /*                         ~OGRGPXDataSource()                          */
      73                 : /************************************************************************/
      74                 : 
      75             237 : OGRGPXDataSource::~OGRGPXDataSource()
      76                 : 
      77                 : {
      78             237 :     if ( fpOutput != NULL )
      79                 :     {
      80               4 :         if (nLastRteId != -1)
      81               0 :             PrintLine("</rte>");
      82               4 :         else if (nLastTrkId != -1)
      83                 :         {
      84               2 :             PrintLine("  </trkseg>");
      85               2 :             PrintLine("</trk>");
      86                 :         }
      87               4 :         PrintLine("</gpx>");
      88               4 :         if ( bIsBackSeekable )
      89                 :         {
      90                 :             /* Write the <bound> element in the reserved space */
      91               4 :             if (dfMinLon <= dfMaxLon)
      92                 :             {
      93                 :                 char szMetadata[SPACE_FOR_METADATA+1];
      94                 :                 int nRet = snprintf(szMetadata, SPACE_FOR_METADATA,
      95                 :                          "<metadata><bounds minlat=\"%.15f\" minlon=\"%.15f\" maxlat=\"%.15f\" maxlon=\"%.15f\"/></metadata>",
      96               4 :                         dfMinLat, dfMinLon, dfMaxLat, dfMaxLon);
      97               4 :                 if (nRet < SPACE_FOR_METADATA)
      98                 :                 {
      99               4 :                     VSIFSeekL(fpOutput, nOffsetBounds, SEEK_SET);
     100               4 :                     VSIFWriteL(szMetadata, 1, strlen(szMetadata), fpOutput);
     101                 :                 }
     102                 :             }
     103               4 :             VSIFCloseL( fpOutput);
     104                 :         }
     105                 :     }
     106                 : 
     107             274 :     for( int i = 0; i < nLayers; i++ )
     108              37 :         delete papoLayers[i];
     109             237 :     CPLFree( papoLayers );
     110             237 :     CPLFree( pszExtensionsNS );
     111             237 :     CPLFree( pszName );
     112             237 :     CPLFree( pszVersion );
     113             237 : }
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                           TestCapability()                           */
     117                 : /************************************************************************/
     118                 : 
     119               0 : int OGRGPXDataSource::TestCapability( const char * pszCap )
     120                 : 
     121                 : {
     122               0 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     123               0 :         return TRUE;
     124               0 :     else if( EQUAL(pszCap,ODsCDeleteLayer) )
     125               0 :         return FALSE;
     126                 :     else
     127               0 :         return FALSE;
     128                 : }
     129                 : 
     130                 : /************************************************************************/
     131                 : /*                              GetLayer()                              */
     132                 : /************************************************************************/
     133                 : 
     134              58 : OGRLayer *OGRGPXDataSource::GetLayer( int iLayer )
     135                 : 
     136                 : {
     137              58 :     if( iLayer < 0 || iLayer >= nLayers )
     138               0 :         return NULL;
     139                 :     else
     140              58 :         return papoLayers[iLayer];
     141                 : }
     142                 : 
     143                 : /************************************************************************/
     144                 : /*                            CreateLayer()                             */
     145                 : /************************************************************************/
     146                 : 
     147               7 : OGRLayer * OGRGPXDataSource::CreateLayer( const char * pszLayerName,
     148                 :                                           OGRSpatialReference *poSRS,
     149                 :                                           OGRwkbGeometryType eType,
     150                 :                                           char ** papszOptions )
     151                 : 
     152                 : {
     153                 :     GPXGeometryType gpxGeomType;
     154              12 :     if (eType == wkbPoint || eType == wkbPoint25D)
     155                 :     {
     156               5 :         if (EQUAL(pszLayerName, "track_points"))
     157               2 :             gpxGeomType = GPX_TRACK_POINT;
     158               3 :         else if (EQUAL(pszLayerName, "route_points"))
     159               1 :             gpxGeomType = GPX_ROUTE_POINT;
     160                 :         else
     161               2 :             gpxGeomType = GPX_WPT;
     162                 :     }
     163               3 :     else if (eType == wkbLineString || eType == wkbLineString25D)
     164                 :     {
     165               1 :         const char *pszForceGPXTrack = CSLFetchNameValue( papszOptions, "FORCE_GPX_TRACK");
     166               1 :         if (pszForceGPXTrack && CSLTestBoolean(pszForceGPXTrack))
     167               0 :             gpxGeomType = GPX_TRACK;
     168                 :         else
     169               1 :             gpxGeomType = GPX_ROUTE;
     170                 :     }
     171               2 :     else if (eType == wkbMultiLineString || eType == wkbMultiLineString25D)
     172                 :     {
     173               1 :         const char *pszForceGPXRoute = CSLFetchNameValue( papszOptions, "FORCE_GPX_ROUTE");
     174               1 :         if (pszForceGPXRoute && CSLTestBoolean(pszForceGPXRoute))
     175               0 :             gpxGeomType = GPX_ROUTE;
     176                 :         else
     177               1 :             gpxGeomType = GPX_TRACK;
     178                 :     }
     179               0 :     else if (eType == wkbUnknown)
     180                 :     {
     181                 :         CPLError(CE_Failure, CPLE_NotSupported,
     182               0 :                  "Cannot create GPX layer %s with unknown geometry type", pszLayerName);
     183               0 :         return NULL;
     184                 :     }
     185                 :     else
     186                 :     {
     187                 :         CPLError( CE_Failure, CPLE_NotSupported,
     188                 :                     "Geometry type of `%s' not supported in GPX.\n",
     189               0 :                     OGRGeometryTypeToName(eType) );
     190               0 :         return NULL;
     191                 :     }
     192               7 :     nLayers++;
     193               7 :     papoLayers = (OGRGPXLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGPXLayer*));
     194               7 :     papoLayers[nLayers-1] = new OGRGPXLayer( pszName, pszLayerName, gpxGeomType, this, TRUE );
     195                 :     
     196               7 :     return papoLayers[nLayers-1];
     197                 : }
     198                 : 
     199                 : #ifdef HAVE_EXPAT
     200                 : 
     201                 : /************************************************************************/
     202                 : /*                startElementValidateCbk()                             */
     203                 : /************************************************************************/
     204                 : 
     205            1989 : void OGRGPXDataSource::startElementValidateCbk(const char *pszName, const char **ppszAttr)
     206                 : {
     207            1989 :     if (validity == GPX_VALIDITY_UNKNOWN)
     208                 :     {
     209              36 :         if (strcmp(pszName, "gpx") == 0)
     210                 :         {
     211                 :             int i;
     212               6 :             validity = GPX_VALIDITY_VALID;
     213               8 :             for(i=0; ppszAttr[i] != NULL; i+= 2)
     214                 :             {
     215               8 :                 if (strcmp(ppszAttr[i], "version") == 0)
     216                 :                 {
     217               6 :                     pszVersion = CPLStrdup(ppszAttr[i+1]);
     218               6 :                     break;
     219                 :                 }
     220                 :             }
     221                 :         }
     222                 :         else
     223                 :         {
     224              30 :             validity = GPX_VALIDITY_INVALID;
     225                 :         }
     226                 :     }
     227            1953 :     else if (validity == GPX_VALIDITY_VALID)
     228                 :     {
     229             170 :         if (strcmp(pszName, "extensions") == 0)
     230                 :         {
     231               4 :             bUseExtensions = TRUE;
     232                 :         }
     233             170 :         nElementsRead++;
     234                 :     }
     235            1989 : }
     236                 : 
     237                 : 
     238                 : /************************************************************************/
     239                 : /*                      dataHandlerValidateCbk()                        */
     240                 : /************************************************************************/
     241                 : 
     242            6499 : void OGRGPXDataSource::dataHandlerValidateCbk(const char *data, int nLen)
     243                 : {
     244            6499 :     nDataHandlerCounter ++;
     245            6499 :     if (nDataHandlerCounter >= BUFSIZ)
     246                 :     {
     247               0 :         CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
     248               0 :         XML_StopParser(oCurrentParser, XML_FALSE);
     249                 :     }
     250            6499 : }
     251                 : 
     252                 : 
     253            1989 : static void XMLCALL startElementValidateCbk(void *pUserData, const char *pszName, const char **ppszAttr)
     254                 : {
     255            1989 :     OGRGPXDataSource* poDS = (OGRGPXDataSource*) pUserData;
     256            1989 :     poDS->startElementValidateCbk(pszName, ppszAttr);
     257            1989 : }
     258                 : 
     259            6499 : static void XMLCALL dataHandlerValidateCbk(void *pUserData, const char *data, int nLen)
     260                 : {
     261            6499 :     OGRGPXDataSource* poDS = (OGRGPXDataSource*) pUserData;
     262            6499 :     poDS->dataHandlerValidateCbk(data, nLen);
     263            6499 : }
     264                 : #endif
     265                 : 
     266                 : /************************************************************************/
     267                 : /*                                Open()                                */
     268                 : /************************************************************************/
     269                 : 
     270             233 : int OGRGPXDataSource::Open( const char * pszFilename, int bUpdateIn)
     271                 : 
     272                 : {
     273             233 :     if (bUpdateIn)
     274                 :     {
     275                 :         CPLError(CE_Failure, CPLE_NotSupported,
     276               0 :                     "OGR/GPX driver does not support opening a file in update mode");
     277               0 :         return FALSE;
     278                 :     }
     279                 : #ifdef HAVE_EXPAT
     280             233 :     pszName = CPLStrdup( pszFilename );
     281                 : 
     282                 : /* -------------------------------------------------------------------- */
     283                 : /*      Try to open the file.                                           */
     284                 : /* -------------------------------------------------------------------- */
     285             233 :     VSILFILE* fp = VSIFOpenL(pszFilename, "r");
     286             233 :     if (fp == NULL)
     287              67 :         return FALSE;
     288                 :     
     289             166 :     validity = GPX_VALIDITY_UNKNOWN;
     290             166 :     CPLFree(pszVersion);
     291             166 :     pszVersion = NULL;
     292             166 :     bUseExtensions = FALSE;
     293             166 :     nElementsRead = 0;
     294                 :     
     295             166 :     XML_Parser oParser = OGRCreateExpatXMLParser();
     296             166 :     oCurrentParser = oParser;
     297             166 :     XML_SetUserData(oParser, this);
     298             166 :     XML_SetElementHandler(oParser, ::startElementValidateCbk, NULL);
     299             166 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerValidateCbk);
     300                 :     
     301                 :     char aBuf[BUFSIZ];
     302                 :     int nDone;
     303                 :     unsigned int nLen;
     304             166 :     int nCount = 0;
     305                 :     
     306                 :     /* Begin to parse the file and look for the <gpx> element */
     307                 :     /* It *MUST* be the first element of an XML file */
     308                 :     /* So once we have read the first element, we know if we can */
     309                 :     /* handle the file or not with that driver */
     310               7 :     do
     311                 :     {
     312             166 :         nDataHandlerCounter = 0;
     313             166 :         nLen = (unsigned int) VSIFReadL( aBuf, 1, sizeof(aBuf), fp );
     314             166 :         nDone = VSIFEofL(fp);
     315             166 :         if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
     316                 :         {
     317             127 :             if (nLen <= BUFSIZ-1)
     318              90 :                 aBuf[nLen] = 0;
     319                 :             else
     320              37 :                 aBuf[BUFSIZ-1] = 0;
     321             127 :             if (strstr(aBuf, "<?xml") && strstr(aBuf, "<gpx"))
     322                 :             {
     323                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     324                 :                         "XML parsing of GPX file failed : %s at line %d, column %d",
     325                 :                         XML_ErrorString(XML_GetErrorCode(oParser)),
     326                 :                         (int)XML_GetCurrentLineNumber(oParser),
     327               0 :                         (int)XML_GetCurrentColumnNumber(oParser));
     328                 :             }
     329             127 :             validity = GPX_VALIDITY_INVALID;
     330             127 :             break;
     331                 :         }
     332              39 :         if (validity == GPX_VALIDITY_INVALID)
     333                 :         {
     334              29 :             break;
     335                 :         }
     336              10 :         else if (validity == GPX_VALIDITY_VALID)
     337                 :         {
     338                 :             /* If we have recognized the <gpx> element, now we try */
     339                 :             /* to recognize if they are <extensions> tags */
     340                 :             /* But we stop to look for after an arbitrary number of tags */
     341               6 :             if (bUseExtensions)
     342               3 :                 break;
     343               3 :             else if (nElementsRead > 200)
     344               0 :                 break;
     345                 :         }
     346                 :         else
     347                 :         {
     348                 :             /* After reading 50 * BUFSIZE bytes, and not finding whether the file */
     349                 :             /* is GPX or not, we give up and fail silently */
     350               4 :             nCount ++;
     351               4 :             if (nCount == 50)
     352               0 :                 break;
     353                 :         }
     354                 :     } while (!nDone && nLen > 0 );
     355                 :     
     356             166 :     XML_ParserFree(oParser);
     357                 :     
     358             166 :     VSIFCloseL(fp);
     359                 :     
     360             166 :     if (validity == GPX_VALIDITY_VALID)
     361                 :     {
     362               6 :         CPLDebug("GPX", "%s seems to be a GPX file.", pszFilename);
     363               6 :         if (bUseExtensions)
     364               3 :             CPLDebug("GPX", "It uses <extensions>");
     365                 : 
     366               6 :         if (pszVersion == NULL)
     367                 :         {
     368                 :             /* Default to 1.1 */
     369                 :             CPLError(CE_Warning, CPLE_AppDefined, "GPX schema version is unknown. "
     370               0 :                      "The driver may not be able to handle the file correctly and will behave as if it is GPX 1.1.");
     371               0 :             pszVersion = CPLStrdup("1.1");
     372                 :         }
     373               6 :         else if (strcmp(pszVersion, "1.0") == 0 || strcmp(pszVersion, "1.1") == 0)
     374                 :         {
     375                 :             /* Fine */
     376                 :         }
     377                 :         else
     378                 :         {
     379                 :             CPLError(CE_Warning, CPLE_AppDefined,
     380                 :                      "GPX schema version '%s' is not handled by the driver. "
     381               0 :                      "The driver may not be able to handle the file correctly and will behave as if it is GPX 1.1.", pszVersion);
     382                 :         }
     383                 : 
     384               6 :         nLayers = 5;
     385               6 :         papoLayers = (OGRGPXLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGPXLayer*));
     386               6 :         papoLayers[0] = new OGRGPXLayer( pszName, "waypoints", GPX_WPT, this, FALSE );
     387              12 :         papoLayers[1] = new OGRGPXLayer( pszName, "routes", GPX_ROUTE, this, FALSE );
     388              12 :         papoLayers[2] = new OGRGPXLayer( pszName, "tracks", GPX_TRACK, this, FALSE );
     389              12 :         papoLayers[3] = new OGRGPXLayer( pszName, "route_points", GPX_ROUTE_POINT, this, FALSE );
     390              12 :         papoLayers[4] = new OGRGPXLayer( pszName, "track_points", GPX_TRACK_POINT, this, FALSE );
     391                 :     }
     392                 : 
     393             166 :     return (validity == GPX_VALIDITY_VALID);
     394                 : #else
     395                 :     char aBuf[256];
     396                 :     VSILFILE* fp = VSIFOpenL(pszFilename, "r");
     397                 :     if (fp)
     398                 :     {
     399                 :         unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, 255, fp );
     400                 :         aBuf[nLen] = 0;
     401                 :         if (strstr(aBuf, "<?xml") && strstr(aBuf, "<gpx"))
     402                 :         {
     403                 :             CPLError(CE_Failure, CPLE_NotSupported,
     404                 :                     "OGR/GPX driver has not been built with read support. Expat library required");
     405                 :         }
     406                 :         VSIFCloseL(fp);
     407                 :     }
     408                 :     return FALSE;
     409                 : #endif
     410                 : }
     411                 : 
     412                 : 
     413                 : /************************************************************************/
     414                 : /*                               Create()                               */
     415                 : /************************************************************************/
     416                 : 
     417               4 : int OGRGPXDataSource::Create( const char *pszFilename, 
     418                 :                               char **papszOptions )
     419                 : {
     420               4 :     if( fpOutput != NULL)
     421                 :     {
     422               0 :         CPLAssert( FALSE );
     423               0 :         return FALSE;
     424                 :     }
     425                 : 
     426               4 :     if (strcmp(pszFilename, "/dev/stdout") == 0)
     427               0 :         pszFilename = "/vsistdout/";
     428                 : 
     429                 : /* -------------------------------------------------------------------- */
     430                 : /*     Do not override exiting file.                                    */
     431                 : /* -------------------------------------------------------------------- */
     432                 :     VSIStatBufL sStatBuf;
     433                 : 
     434               4 :     if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
     435                 :     {
     436                 :         CPLError(CE_Failure, CPLE_NotSupported,
     437                 :                  "You have to delete %s before being able to create it with the GPX driver",
     438               0 :                  pszFilename);
     439               0 :         return FALSE;
     440                 :     }
     441                 :     
     442                 : /* -------------------------------------------------------------------- */
     443                 : /*      Create the output file.                                         */
     444                 : /* -------------------------------------------------------------------- */
     445                 : 
     446               4 :     pszName = CPLStrdup( pszFilename );
     447                 : 
     448               4 :     if( strcmp(pszName, "/vsistdout/") == 0 )
     449                 :     {
     450               0 :         bIsBackSeekable = FALSE;
     451               0 :         fpOutput = VSIFOpenL( pszFilename, "w" );
     452                 :     }
     453                 :     else
     454               4 :         fpOutput = VSIFOpenL( pszFilename, "w+" );
     455               4 :     if( fpOutput == NULL )
     456                 :     {
     457                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     458                 :                   "Failed to create GPX file %s.", 
     459               0 :                   pszFilename );
     460               0 :         return FALSE;
     461                 :     }
     462                 : 
     463                 : /* -------------------------------------------------------------------- */
     464                 : /*      End of line character.                                          */
     465                 : /* -------------------------------------------------------------------- */
     466               4 :     const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT");
     467                 : 
     468                 :     int bUseCRLF;
     469               4 :     if( pszCRLFFormat == NULL )
     470                 :     {
     471                 : #ifdef WIN32
     472                 :         bUseCRLF = TRUE;
     473                 : #else
     474               3 :         bUseCRLF = FALSE;
     475                 : #endif
     476                 :     }
     477               1 :     else if( EQUAL(pszCRLFFormat,"CRLF") )
     478               0 :         bUseCRLF = TRUE;
     479               1 :     else if( EQUAL(pszCRLFFormat,"LF") )
     480               1 :         bUseCRLF = FALSE;
     481                 :     else
     482                 :     {
     483                 :         CPLError( CE_Warning, CPLE_AppDefined, 
     484                 :                   "LINEFORMAT=%s not understood, use one of CRLF or LF.",
     485               0 :                   pszCRLFFormat );
     486                 : #ifdef WIN32
     487                 :         bUseCRLF = TRUE;
     488                 : #else
     489               0 :         bUseCRLF = FALSE;
     490                 : #endif
     491                 :     }
     492               4 :     pszEOL = (bUseCRLF) ? "\r\n" : "\n";
     493                 : 
     494                 : /* -------------------------------------------------------------------- */
     495                 : /*      Look at use extensions options.                                 */
     496                 : /* -------------------------------------------------------------------- */
     497               4 :     const char* pszUseExtensions = CSLFetchNameValue( papszOptions, "GPX_USE_EXTENSIONS");
     498               4 :     const char* pszExtensionsNSURL = NULL;
     499               4 :     if (pszUseExtensions && CSLTestBoolean(pszUseExtensions))
     500                 :     {
     501               1 :         bUseExtensions = TRUE;
     502                 : 
     503               1 :         const char* pszExtensionsNSOption = CSLFetchNameValue( papszOptions, "GPX_EXTENSIONS_NS");
     504               1 :         const char* pszExtensionsNSURLOption = CSLFetchNameValue( papszOptions, "GPX_EXTENSIONS_NS_URL");
     505               1 :         if (pszExtensionsNSOption && pszExtensionsNSURLOption)
     506                 :         {
     507               0 :             pszExtensionsNS = CPLStrdup(pszExtensionsNSOption);
     508               0 :             pszExtensionsNSURL = pszExtensionsNSURLOption;
     509                 :         }
     510                 :         else
     511                 :         {
     512               1 :             pszExtensionsNS = CPLStrdup("ogr");
     513               1 :             pszExtensionsNSURL = "http://osgeo.org/gdal";
     514                 :         }
     515                 :     }
     516                 :     
     517                 : /* -------------------------------------------------------------------- */
     518                 : /*     Output header of GPX file.                                       */
     519                 : /* -------------------------------------------------------------------- */
     520               4 :     PrintLine("<?xml version=\"1.0\"?>");
     521               4 :     VSIFPrintfL(fpOutput, "<gpx version=\"1.1\" creator=\"GDAL " GDAL_RELEASE_NAME "\" ");
     522               4 :     VSIFPrintfL(fpOutput, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
     523               4 :     if (bUseExtensions)
     524               1 :         VSIFPrintfL(fpOutput, "xmlns:%s=\"%s\" ", pszExtensionsNS, pszExtensionsNSURL);
     525               4 :     VSIFPrintfL(fpOutput, "xmlns=\"http://www.topografix.com/GPX/1/1\" ");
     526               4 :     PrintLine("xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">");
     527               4 :     if (bIsBackSeekable)
     528                 :     {
     529                 :       /* Reserve space for <metadata><bounds/></metadata> */
     530                 :       char szMetadata[SPACE_FOR_METADATA+1];
     531               4 :       memset(szMetadata, ' ', SPACE_FOR_METADATA);
     532               4 :       szMetadata[SPACE_FOR_METADATA] = '\0';
     533               4 :       nOffsetBounds = (int) VSIFTellL(fpOutput);
     534               4 :       PrintLine("%s", szMetadata);
     535                 :     }
     536                 : 
     537               4 :     return TRUE;
     538                 : }
     539                 : 
     540                 : /************************************************************************/
     541                 : /*                             AddCoord()                               */
     542                 : /************************************************************************/
     543                 : 
     544              20 : void OGRGPXDataSource::AddCoord(double dfLon, double dfLat)
     545                 : {
     546              20 :     if (dfLon < dfMinLon) dfMinLon = dfLon;
     547              20 :     if (dfLat < dfMinLat) dfMinLat = dfLat;
     548              20 :     if (dfLon > dfMaxLon) dfMaxLon = dfLon;
     549              20 :     if (dfLat > dfMaxLat) dfMaxLat = dfLat;
     550              20 : }
     551                 : 
     552                 : /************************************************************************/
     553                 : /*                            PrintLine()                               */
     554                 : /************************************************************************/
     555                 : 
     556             125 : void OGRGPXDataSource::PrintLine(const char *fmt, ...)
     557                 : {
     558             125 :     CPLString osWork;
     559                 :     va_list args;
     560                 : 
     561             125 :     va_start( args, fmt );
     562             125 :     osWork.vPrintf( fmt, args );
     563             125 :     va_end( args );
     564                 : 
     565             125 :     VSIFPrintfL(fpOutput, "%s%s", osWork.c_str(), pszEOL);
     566             125 : }

Generated by: LCOV version 1.7