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