int OGRGPSBabelWriteDataSource::Convert()
{
    int nRet = -1;
    if( osTmpFileName.size() > 0 && pszFilename != NULL &&
         pszGPSBabelDriverName != NULL )
    {
        if (OGRGPSBabelDataSource::IsSpecialFile(pszFilename))
        {
            /* Special file : don't try to open it */
            VSILFILE* tmpfp = VSIFOpenL(osTmpFileName.c_str(), "rb");
            if (tmpfp)
            {
                const char* const argv[] = {
                    "gpsbabel", "-i", "gpx", "-f", "-",
                    "-o", pszGPSBabelDriverName, "-F", pszFilename, NULL };
                nRet = CPLSpawn(argv, tmpfp, NULL, TRUE);

                VSIFCloseL(tmpfp);
                tmpfp = NULL;
            }
        }
        else
        {
            VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
            if (fp == NULL)
            {
                CPLError( CE_Failure, CPLE_AppDefined,
                          "Cannot open file %s", pszFilename );
            }
            else
            {
                VSILFILE* tmpfp = VSIFOpenL(osTmpFileName.c_str(), "rb");
                if (tmpfp)
                {
                    const char* const argv[] = {
                        "gpsbabel", "-i", "gpx", "-f", "-",
                        "-o", pszGPSBabelDriverName, "-F", "-", NULL };
                    nRet = CPLSpawn(argv, tmpfp, fp, TRUE);

                    VSIFCloseL(tmpfp);
                    tmpfp = NULL;
                }

                VSIFCloseL(fp);
                fp = NULL;
            }
        }

        VSIUnlink(osTmpFileName.c_str());
        osTmpFileName = "";
    }

    return nRet == 0;
}
static bool OGRGPSBabelDriverIdentifyInternal(
    GDALOpenInfo* poOpenInfo,
    const char** ppszGSPBabelDriverName )
{
    if( STARTS_WITH_CI(poOpenInfo->pszFilename, "GPSBABEL:") )
        return true;

    const char* pszGPSBabelDriverName = NULL;
    if( poOpenInfo->fpL == NULL )
            return false;

    if (memcmp(poOpenInfo->pabyHeader, "MsRcd", 5) == 0)
        pszGPSBabelDriverName = "mapsource";
    else if (memcmp(poOpenInfo->pabyHeader, "MsRcf", 5) == 0)
        pszGPSBabelDriverName = "gdb";
    else if (strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader), "<osm") != NULL)
        pszGPSBabelDriverName = "osm";
    else if (strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader), "$GPGSA") != NULL ||
                strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader), "$GPGGA") != NULL)
        pszGPSBabelDriverName = "nmea";
    else if (STARTS_WITH_CI((const char*)poOpenInfo->pabyHeader, "OziExplorer"))
        pszGPSBabelDriverName = "ozi";
    else if (strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader), "Grid") &&
                strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader), "Datum") &&
                strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader), "Header"))
        pszGPSBabelDriverName = "garmin_txt";
    else if (poOpenInfo->pabyHeader[0] == 13 && poOpenInfo->pabyHeader[10] == 'M' && poOpenInfo->pabyHeader[11] == 'S' &&
                (poOpenInfo->pabyHeader[12] >= '0' && poOpenInfo->pabyHeader[12] <= '9') &&
                (poOpenInfo->pabyHeader[13] >= '0' && poOpenInfo->pabyHeader[13] <= '9') &&
                poOpenInfo->pabyHeader[12] * 10 + poOpenInfo->pabyHeader[13] >= 30 &&
                (poOpenInfo->pabyHeader[14] == 1 || poOpenInfo->pabyHeader[14] == 2) && poOpenInfo->pabyHeader[15] == 0 &&
                poOpenInfo->pabyHeader[16] == 0 && poOpenInfo->pabyHeader[17] == 0)
        pszGPSBabelDriverName = "mapsend";
    else if (strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader), "$PMGNWPL") != NULL ||
                strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader), "$PMGNRTE") != NULL)
        pszGPSBabelDriverName = "magellan";
    else if (poOpenInfo->pabyHeader[0] == 'A' &&
                poOpenInfo->pabyHeader[1] >= 'A' && poOpenInfo->pabyHeader[1] <= 'Z' &&
                poOpenInfo->pabyHeader[2] >= 'A' && poOpenInfo->pabyHeader[2] <= 'Z' &&
                poOpenInfo->pabyHeader[3] >= 'A' && poOpenInfo->pabyHeader[3] <= 'Z' &&
                EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "igc") )
        pszGPSBabelDriverName = "igc";

    static int bGPSBabelFound = -1;
    if( pszGPSBabelDriverName != NULL && bGPSBabelFound < 0 )
    {
#ifndef WIN32
        VSIStatBufL sStat;
        bGPSBabelFound = VSIStatL("/usr/bin/gpsbabel", &sStat) == 0;
        if( !bGPSBabelFound )
#endif
        {
            const char* const apszArgs[] = { "gpsbabel", "-V", NULL };
            CPLString osTmpFileName("/vsimem/gpsbabel_tmp.tmp");
            VSILFILE* tmpfp = VSIFOpenL(osTmpFileName, "wb");
            bGPSBabelFound = (CPLSpawn(apszArgs, NULL, tmpfp, FALSE) == 0);
            VSIFCloseL(tmpfp);
            VSIUnlink(osTmpFileName);
        }
    }

    if( bGPSBabelFound )
        *ppszGSPBabelDriverName = pszGPSBabelDriverName;
    return *ppszGSPBabelDriverName != NULL;
}
int OGRGPSBabelDataSource::Open( const char * pszDatasourceName,
                                 const char* pszGPSBabelDriverNameIn,
                                 char** papszOpenOptionsIn )

{
    if (!STARTS_WITH_CI(pszDatasourceName, "GPSBABEL:"))
    {
        CPLAssert(pszGPSBabelDriverNameIn);
        pszGPSBabelDriverName = CPLStrdup(pszGPSBabelDriverNameIn);
        pszFilename = CPLStrdup(pszDatasourceName);
    }
    else
    {
        if( CSLFetchNameValue(papszOpenOptionsIn, "FILENAME") )
            pszFilename = CPLStrdup(CSLFetchNameValue(papszOpenOptionsIn,
                                                      "FILENAME"));

        if( CSLFetchNameValue(papszOpenOptionsIn, "GPSBABEL_DRIVER") )
        {
            if( pszFilename == NULL )
            {
                CPLError(CE_Failure, CPLE_AppDefined, "Missing FILENAME");
                return FALSE;
            }

            pszGPSBabelDriverName
                = CPLStrdup(CSLFetchNameValue(papszOpenOptionsIn, "DRIVER"));

            /* A bit of validation to avoid command line injection */
            if (!IsValidDriverName(pszGPSBabelDriverName))
                return FALSE;
        }
    }

    pszName = CPLStrdup( pszDatasourceName );

    bool bExplicitFeatures = false;
    bool bWaypoints = true;
    bool bTracks = true;
    bool bRoutes = true;

    if (pszGPSBabelDriverName == NULL)
    {
        const char* pszSep = strchr(pszDatasourceName + 9, ':');
        if (pszSep == NULL)
        {
            CPLError( CE_Failure, CPLE_AppDefined,
                      "Wrong syntax. Expected GPSBabel:driver_name:file_name");
            return FALSE;
        }

        pszGPSBabelDriverName = CPLStrdup(pszDatasourceName + 9);
        *(strchr(pszGPSBabelDriverName, ':')) = '\0';

        /* A bit of validation to avoid command line injection */
        if (!IsValidDriverName(pszGPSBabelDriverName))
            return FALSE;

        /* Parse optional features= option */
        if (STARTS_WITH_CI(pszSep+1, "features="))
        {
            const char* pszNextSep = strchr(pszSep+1, ':');
            if (pszNextSep == NULL)
            {
                CPLError(CE_Failure, CPLE_AppDefined,
                        "Wrong syntax. Expected "
                         "GPSBabel:driver_name[,options]*:["
                         "features=waypoints,tracks,routes:]file_name");
                return FALSE;
            }

            char* pszFeatures = CPLStrdup(pszSep+1+9);
            *strchr(pszFeatures, ':') = 0;
            char** papszTokens = CSLTokenizeString(pszFeatures);
            char** papszIter = papszTokens;
            bool bErr = false;
            bExplicitFeatures = true;
            bWaypoints = false;
            bTracks = false;
            bRoutes = false;
            while(papszIter && *papszIter)
            {
                if (EQUAL(*papszIter, "waypoints"))
                    bWaypoints = true;
                else if (EQUAL(*papszIter, "tracks"))
                    bTracks = true;
                else if (EQUAL(*papszIter, "routes"))
                    bRoutes = true;
                else
                {
                    CPLError( CE_Failure, CPLE_AppDefined,
                              "Wrong value for 'features' options");
                    bErr = true;
                }
                papszIter++;
            }
            CSLDestroy(papszTokens);
            CPLFree(pszFeatures);

            if (bErr)
                return FALSE;

            pszSep = pszNextSep;
        }

        if( pszFilename == NULL )
            pszFilename = CPLStrdup(pszSep+1);
    }

    const char* pszOptionUseTempFile = CPLGetConfigOption("USE_TEMPFILE", NULL);
    if (pszOptionUseTempFile && CPLTestBool(pszOptionUseTempFile))
        osTmpFileName = CPLGenerateTempFilename(NULL);
    else
        osTmpFileName.Printf("/vsimem/ogrgpsbabeldatasource_%p", this);

    bool bRet = false;
    if (IsSpecialFile(pszFilename))
    {
        /* Special file : don't try to open it */
        char** argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
                              bTracks, pszGPSBabelDriverName, pszFilename);
        VSILFILE* tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");
        bRet = (CPLSpawn(argv, NULL, tmpfp, TRUE) == 0);
        VSIFCloseL(tmpfp);
        tmpfp = NULL;
        CSLDestroy(argv);
        argv = NULL;
    }
    else
    {
        VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
        if (fp == NULL)
        {
            CPLError(CE_Failure, CPLE_AppDefined,
                    "Cannot open file %s", pszFilename);
            return FALSE;
        }

        char** argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
                              bTracks, pszGPSBabelDriverName, "-");

        VSILFILE* tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");

        CPLPushErrorHandler(CPLQuietErrorHandler);
        bRet = (CPLSpawn(argv, fp, tmpfp, TRUE) == 0);
        CPLPopErrorHandler();

        CSLDestroy(argv);
        argv = NULL;

        CPLErr nLastErrorType = CPLGetLastErrorType();
        CPLErrorNum nLastErrorNo = CPLGetLastErrorNo();
        CPLString osLastErrorMsg = CPLGetLastErrorMsg();

        VSIFCloseL(tmpfp);
        tmpfp = NULL;

        VSIFCloseL(fp);
        fp = NULL;

        if (!bRet)
        {
            if ( strstr(osLastErrorMsg.c_str(),
                        "This format cannot be used in piped commands") == NULL)
            {
                CPLError( nLastErrorType, nLastErrorNo, "%s",
                          osLastErrorMsg.c_str());
            }
            else
            {
                VSIStatBuf sStatBuf;
                if (VSIStat(pszFilename, &sStatBuf) != 0)
                {
                    CPLError( CE_Failure, CPLE_NotSupported,
                              "Driver %s only supports real (non virtual) "
                              "files",
                              pszGPSBabelDriverName );
                    return FALSE;
                }

                /* Try without piping in */
                argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
                              bTracks, pszGPSBabelDriverName, pszFilename);
                tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");
                bRet = (CPLSpawn(argv, NULL, tmpfp, TRUE) == 0);
                VSIFCloseL(tmpfp);
                tmpfp = NULL;

                CSLDestroy(argv);
                argv = NULL;
            }
        }
    }


    if (bRet)
    {
        poGPXDS = static_cast<GDALDataset *>(
            GDALOpenEx( osTmpFileName.c_str(),
                        GDAL_OF_VECTOR, NULL, NULL, NULL ) );
        if (poGPXDS)
        {
            if (bWaypoints)
            {
                OGRLayer* poLayer = poGPXDS->GetLayerByName("waypoints");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
            }

            if (bRoutes)
            {
                OGRLayer* poLayer = poGPXDS->GetLayerByName("routes");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
                poLayer = poGPXDS->GetLayerByName("route_points");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
            }

            if (bTracks)
            {
                OGRLayer* poLayer = poGPXDS->GetLayerByName("tracks");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
                poLayer = poGPXDS->GetLayerByName("track_points");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
            }
        }
    }

    return nLayers > 0;
}
int OGRGPSBabelDataSource::Open( const char * pszDatasourceName, int bUpdateIn)

{
    int bExplicitFeatures = FALSE;
    int bWaypoints = TRUE, bTracks = TRUE, bRoutes = TRUE;
    if (bUpdateIn)
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                    "OGR/GPSBabel driver does not support opening a file in update mode");
        return FALSE;
    }

    if (!EQUALN(pszDatasourceName, "GPSBABEL:", 9))
    {
        VSILFILE* fp = VSIFOpenL(pszDatasourceName, "rb");
        if (fp == NULL)
            return FALSE;

        char szHeader[1024 + 1];
        memset(szHeader, 0, 1024+1);
        VSIFReadL(szHeader, 1, 1024, fp);
        if (memcmp(szHeader, "MsRcd", 5) == 0)
            pszGPSBabelDriverName = CPLStrdup("mapsource");
        else if (memcmp(szHeader, "MsRcf", 5) == 0)
            pszGPSBabelDriverName = CPLStrdup("gdb");
        else if (strstr(szHeader, "<osm") != NULL)
            pszGPSBabelDriverName = CPLStrdup("osm");
        else if (strstr(szHeader, "$GPGSA") != NULL ||
                 strstr(szHeader, "$GPGGA") != NULL)
            pszGPSBabelDriverName = CPLStrdup("nmea");
        else if (EQUALN(szHeader, "OziExplorer",11))
            pszGPSBabelDriverName = CPLStrdup("ozi");
        else if (strstr(szHeader, "Grid") && strstr(szHeader, "Datum") && strstr(szHeader, "Header"))
            pszGPSBabelDriverName = CPLStrdup("garmin_txt");
        else if (szHeader[0] == 13 && szHeader[10] == 'M' && szHeader[11] == 'S' &&
                 (szHeader[12] >= '0' && szHeader[12] <= '9') &&
                 (szHeader[13] >= '0' && szHeader[13] <= '9') &&
                 szHeader[12] * 10 + szHeader[13] >= 30 &&
                 (szHeader[14] == 1 || szHeader[14] == 2) && szHeader[15] == 0 &&
                 szHeader[16] == 0 && szHeader[17] == 0)
            pszGPSBabelDriverName = CPLStrdup("mapsend");
        else if (strstr(szHeader, "$PMGNWPL") != NULL ||
                 strstr(szHeader, "$PMGNRTE") != NULL)
            pszGPSBabelDriverName = CPLStrdup("magellan");

        VSIFCloseL(fp);

        if (pszGPSBabelDriverName == NULL)
        {
            return FALSE;
        }

        pszFilename = CPLStrdup(pszDatasourceName);
    }

    pszName = CPLStrdup( pszDatasourceName );

    if (pszGPSBabelDriverName == NULL)
    {
        const char* pszSep = strchr(pszDatasourceName + 9, ':');
        if (pszSep == NULL)
        {
            CPLError(CE_Failure, CPLE_AppDefined,
                    "Wrong syntax. Expected GPSBabel:driver_name:file_name");
            return FALSE;
        }

        pszGPSBabelDriverName = CPLStrdup(pszDatasourceName + 9);
        *(strchr(pszGPSBabelDriverName, ':')) = '\0';

        /* A bit of validation to avoid command line injection */
        if (!IsValidDriverName(pszGPSBabelDriverName))
            return FALSE;

        /* Parse optionnal features= option */
        if (EQUALN(pszSep+1, "features=", 9))
        {
            const char* pszNextSep = strchr(pszSep+1, ':');
            if (pszNextSep == NULL)
            {
                CPLError(CE_Failure, CPLE_AppDefined,
                        "Wrong syntax. Expected GPSBabel:driver_name[,options]*:[features=waypoints,tracks,routes:]file_name");
                return FALSE;
            }

            char* pszFeatures = CPLStrdup(pszSep+1+9);
            *strchr(pszFeatures, ':') = 0;
            char** papszTokens = CSLTokenizeString(pszFeatures);
            char** papszIter = papszTokens;
            int bErr = FALSE;
            bExplicitFeatures = TRUE;
            bWaypoints = bTracks = bRoutes = FALSE;
            while(papszIter && *papszIter)
            {
                if (EQUAL(*papszIter, "waypoints"))
                    bWaypoints = TRUE;
                else if (EQUAL(*papszIter, "tracks"))
                    bTracks = TRUE;
                else if (EQUAL(*papszIter, "routes"))
                    bRoutes = TRUE;
                else
                {
                    CPLError(CE_Failure, CPLE_AppDefined, "Wrong value for 'features' options");
                    bErr = TRUE;
                }
                papszIter ++;
            }
            CSLDestroy(papszTokens);
            CPLFree(pszFeatures);

            if (bErr)
                return FALSE;

            pszSep = pszNextSep;
        }

        pszFilename = CPLStrdup(pszSep+1);
    }

    const char* pszOptionUseTempFile = CPLGetConfigOption("USE_TEMPFILE", NULL);
    if (pszOptionUseTempFile && CSLTestBoolean(pszOptionUseTempFile))
        osTmpFileName = CPLGenerateTempFilename(NULL);
    else
        osTmpFileName.Printf("/vsimem/ogrgpsbabeldatasource_%p", this);

    int bRet = FALSE;
    if (IsSpecialFile(pszFilename))
    {
        /* Special file : don't try to open it */
        char** argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
                              bTracks, pszGPSBabelDriverName, pszFilename);
        VSILFILE* tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");
        bRet = (CPLSpawn(argv, NULL, tmpfp, TRUE) == 0);
        VSIFCloseL(tmpfp);
        tmpfp = NULL;
        CSLDestroy(argv);
        argv = NULL;
    }
    else
    {
        VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
        if (fp == NULL)
        {
            CPLError(CE_Failure, CPLE_AppDefined,
                    "Cannot open file %s", pszFilename);
            return FALSE;
        }

        char** argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
                              bTracks, pszGPSBabelDriverName, "-");

        VSILFILE* tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");

        CPLPushErrorHandler(CPLQuietErrorHandler);
        bRet = (CPLSpawn(argv, fp, tmpfp, TRUE) == 0);
        CPLPopErrorHandler();

        CSLDestroy(argv);
        argv = NULL;

        CPLErr nLastErrorType = CPLGetLastErrorType();
        int nLastErrorNo = CPLGetLastErrorNo();
        CPLString osLastErrorMsg = CPLGetLastErrorMsg();

        VSIFCloseL(tmpfp);
        tmpfp = NULL;

        VSIFCloseL(fp);
        fp = NULL;

        if (!bRet)
        {
            if (strstr(osLastErrorMsg.c_str(), "This format cannot be used in piped commands") == NULL)
            {
                CPLError(nLastErrorType, nLastErrorNo, "%s", osLastErrorMsg.c_str());
            }
            else
            {
                VSIStatBuf sStatBuf;
                if (VSIStat(pszFilename, &sStatBuf) != 0)
                {
                    CPLError(CE_Failure, CPLE_NotSupported,
                            "Driver %s only supports real (non virtual) files", pszGPSBabelDriverName);
                    return FALSE;
                }

                /* Try without piping in */
                argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
                              bTracks, pszGPSBabelDriverName, pszFilename);
                tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");
                bRet = (CPLSpawn(argv, NULL, tmpfp, TRUE) == 0);
                VSIFCloseL(tmpfp);
                tmpfp = NULL;

                CSLDestroy(argv);
                argv = NULL;
            }
        }
    }


    if (bRet)
    {
        poGPXDS = OGRSFDriverRegistrar::Open(osTmpFileName.c_str());
        if (poGPXDS)
        {
            OGRLayer* poLayer;

            if (bWaypoints)
            {
                poLayer = poGPXDS->GetLayerByName("waypoints");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
            }

            if (bRoutes)
            {
                poLayer = poGPXDS->GetLayerByName("routes");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
                poLayer = poGPXDS->GetLayerByName("route_points");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
            }

            if (bTracks)
            {
                poLayer = poGPXDS->GetLayerByName("tracks");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
                poLayer = poGPXDS->GetLayerByName("track_points");
                if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
                    apoLayers[nLayers++] = poLayer;
            }
        }
    }

    return nLayers > 0;
}