Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: OpenGIS Simple Features Reference Implementation 4 : * Purpose: Implements OGRGPSbabelDriver class. 5 : * Author: Even Rouault, <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2010, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "cpl_conv.h" 14 : #include "cpl_spawn.h" 15 : 16 : #include "ogr_gpsbabel.h" 17 : 18 : /************************************************************************/ 19 : /* OGRGPSBabelDriverIdentify() */ 20 : /************************************************************************/ 21 : 22 : static bool 23 45888 : OGRGPSBabelDriverIdentifyInternal(GDALOpenInfo *poOpenInfo, 24 : const char **ppszGSPBabelDriverName) 25 : { 26 45888 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "GPSBABEL:")) 27 19 : return true; 28 : 29 45869 : const char *pszGPSBabelDriverName = nullptr; 30 45869 : if (poOpenInfo->fpL == nullptr) 31 43307 : return false; 32 : 33 2562 : if (memcmp(poOpenInfo->pabyHeader, "MsRcd", 5) == 0) 34 0 : pszGPSBabelDriverName = "mapsource"; 35 2562 : else if (memcmp(poOpenInfo->pabyHeader, "MsRcf", 5) == 0) 36 0 : pszGPSBabelDriverName = "gdb"; 37 2562 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 38 : "<osm") != nullptr) 39 : { 40 0 : if (GDALGetDriverByName("OSM") != nullptr) 41 0 : return false; 42 0 : pszGPSBabelDriverName = "osm"; 43 : } 44 2562 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 45 : "<TrainingCenterDatabase") != nullptr) 46 0 : pszGPSBabelDriverName = "gtrnctr"; 47 2562 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 48 2562 : "$GPGSA") != nullptr || 49 2562 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 50 : "$GPGGA") != nullptr) 51 2 : pszGPSBabelDriverName = "nmea"; 52 2560 : else if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, 53 : "OziExplorer")) 54 0 : pszGPSBabelDriverName = "ozi"; 55 2560 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 56 0 : "Grid") && 57 0 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 58 0 : "Datum") && 59 0 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 60 : "Header")) 61 0 : pszGPSBabelDriverName = "garmin_txt"; 62 2560 : else if (poOpenInfo->pabyHeader[0] == 13 && 63 0 : poOpenInfo->pabyHeader[10] == 'M' && 64 0 : poOpenInfo->pabyHeader[11] == 'S' && 65 0 : (poOpenInfo->pabyHeader[12] >= '0' && 66 0 : poOpenInfo->pabyHeader[12] <= '9') && 67 0 : (poOpenInfo->pabyHeader[13] >= '0' && 68 0 : poOpenInfo->pabyHeader[13] <= '9') && 69 0 : poOpenInfo->pabyHeader[12] * 10 + poOpenInfo->pabyHeader[13] >= 70 0 : 30 && 71 0 : (poOpenInfo->pabyHeader[14] == 1 || 72 0 : poOpenInfo->pabyHeader[14] == 2) && 73 0 : poOpenInfo->pabyHeader[15] == 0 && 74 0 : poOpenInfo->pabyHeader[16] == 0 && poOpenInfo->pabyHeader[17] == 0) 75 0 : pszGPSBabelDriverName = "mapsend"; 76 2560 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 77 2560 : "$PMGNWPL") != nullptr || 78 2560 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), 79 : "$PMGNRTE") != nullptr) 80 0 : pszGPSBabelDriverName = "magellan"; 81 5685 : else if (poOpenInfo->pabyHeader[0] == 'A' && 82 565 : poOpenInfo->pabyHeader[1] >= 'A' && 83 565 : poOpenInfo->pabyHeader[1] <= 'Z' && 84 565 : poOpenInfo->pabyHeader[2] >= 'A' && 85 565 : poOpenInfo->pabyHeader[2] <= 'Z' && 86 565 : poOpenInfo->pabyHeader[3] >= 'A' && 87 3660 : poOpenInfo->pabyHeader[3] <= 'Z' && 88 535 : poOpenInfo->IsExtensionEqualToCI("igc")) 89 0 : pszGPSBabelDriverName = "igc"; 90 : 91 : static int bGPSBabelFound = -1; 92 2562 : if (pszGPSBabelDriverName != nullptr && bGPSBabelFound < 0) 93 : { 94 : #ifndef _WIN32 95 : VSIStatBufL sStat; 96 1 : bGPSBabelFound = VSIStatL("/usr/bin/gpsbabel", &sStat) == 0; 97 1 : if (!bGPSBabelFound) 98 : #endif 99 : { 100 0 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); 101 0 : const char *const apszArgs[] = {"gpsbabel", "-V", nullptr}; 102 : const CPLString osTmpFileName = 103 0 : VSIMemGenerateHiddenFilename("gpsbabel"); 104 0 : VSILFILE *tmpfp = VSIFOpenL(osTmpFileName, "wb"); 105 0 : bGPSBabelFound = CPLSpawn(apszArgs, nullptr, tmpfp, FALSE) == 0; 106 0 : VSIFCloseL(tmpfp); 107 0 : VSIUnlink(osTmpFileName); 108 : } 109 : } 110 : 111 2562 : if (bGPSBabelFound) 112 : { 113 2562 : *ppszGSPBabelDriverName = pszGPSBabelDriverName; 114 : } 115 0 : else if (pszGPSBabelDriverName) 116 : { 117 0 : CPLDebug("GPSBABEL", 118 : "File %s could be recognized by GPSBABEL (sub-driver %s), but " 119 : "binary 'gpsbabel' is missing in the PATH", 120 : poOpenInfo->pszFilename, pszGPSBabelDriverName); 121 : } 122 2562 : return *ppszGSPBabelDriverName != nullptr; 123 : } 124 : 125 45878 : static int OGRGPSBabelDriverIdentify(GDALOpenInfo *poOpenInfo) 126 : { 127 45878 : const char *pszGPSBabelDriverName = nullptr; 128 45878 : return OGRGPSBabelDriverIdentifyInternal(poOpenInfo, 129 45878 : &pszGPSBabelDriverName); 130 : } 131 : 132 : /************************************************************************/ 133 : /* Open() */ 134 : /************************************************************************/ 135 : 136 10 : static GDALDataset *OGRGPSBabelDriverOpen(GDALOpenInfo *poOpenInfo) 137 : 138 : { 139 10 : const char *pszGPSBabelDriverName = nullptr; 140 20 : if (poOpenInfo->eAccess == GA_Update || 141 10 : !OGRGPSBabelDriverIdentifyInternal(poOpenInfo, &pszGPSBabelDriverName)) 142 0 : return nullptr; 143 : 144 10 : OGRGPSBabelDataSource *poDS = new OGRGPSBabelDataSource(); 145 : 146 10 : if (!poDS->Open(poOpenInfo->pszFilename, pszGPSBabelDriverName, 147 : poOpenInfo->papszOpenOptions)) 148 : { 149 5 : delete poDS; 150 5 : poDS = nullptr; 151 : } 152 : 153 10 : return poDS; 154 : } 155 : 156 : /************************************************************************/ 157 : /* Create() */ 158 : /************************************************************************/ 159 : 160 1 : static GDALDataset *OGRGPSBabelDriverCreate(const char *pszName, 161 : int /* nBands */, int /* nXSize */, 162 : int /* nYSize */, 163 : GDALDataType /* eDT */, 164 : char **papszOptions) 165 : { 166 1 : OGRGPSBabelWriteDataSource *poDS = new OGRGPSBabelWriteDataSource(); 167 : 168 1 : if (!poDS->Create(pszName, papszOptions)) 169 : { 170 0 : delete poDS; 171 0 : poDS = nullptr; 172 : } 173 : 174 1 : return poDS; 175 : } 176 : 177 : /************************************************************************/ 178 : /* Delete() */ 179 : /************************************************************************/ 180 : 181 1 : static CPLErr OGRGPSBabelDriverDelete(const char *pszFilename) 182 : 183 : { 184 1 : if (VSIUnlink(pszFilename) == 0) 185 0 : return CE_None; 186 : 187 1 : return CE_Failure; 188 : } 189 : 190 : /************************************************************************/ 191 : /* RegisterOGRGPSBabel() */ 192 : /************************************************************************/ 193 : 194 1682 : void RegisterOGRGPSBabel() 195 : { 196 1682 : if (!GDAL_CHECK_VERSION("OGR/GPSBabel driver")) 197 0 : return; 198 : 199 1682 : if (GDALGetDriverByName("GPSBabel") != nullptr) 200 301 : return; 201 : 202 1381 : GDALDriver *poDriver = new GDALDriver(); 203 : 204 1381 : poDriver->SetDescription("GPSBabel"); 205 1381 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 206 1381 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 207 1381 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GPSBabel"); 208 1381 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 209 1381 : "drivers/vector/gpsbabel.html"); 210 1381 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "mps gdb osm tcx igc"); 211 1381 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 212 : 213 1381 : poDriver->SetMetadataItem(GDAL_DMD_CONNECTION_PREFIX, "GPSBABEL:"); 214 : 215 1381 : poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, 216 : "<OpenOptionList>" 217 : " <Option name='FILENAME' type='string' " 218 : "description='Filename to open'/>" 219 : " <Option name='GPSBABEL_DRIVER' type='string' " 220 : "description='Name of the GPSBabel to use'/>" 221 1381 : "</OpenOptionList>"); 222 : 223 1381 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST, 224 : "<CreationOptionList>" 225 : " <Option name='GPSBABEL_DRIVER' type='string' " 226 : "description='Name of the GPSBabel to use'/>" 227 1381 : "</CreationOptionList>"); 228 : 229 1381 : poDriver->pfnOpen = OGRGPSBabelDriverOpen; 230 1381 : poDriver->pfnIdentify = OGRGPSBabelDriverIdentify; 231 1381 : poDriver->pfnCreate = OGRGPSBabelDriverCreate; 232 1381 : poDriver->pfnDelete = OGRGPSBabelDriverDelete; 233 : 234 1381 : GetGDALDriverManager()->RegisterDriver(poDriver); 235 : }