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 45428 : OGRGPSBabelDriverIdentifyInternal(GDALOpenInfo *poOpenInfo,
24 : const char **ppszGSPBabelDriverName)
25 : {
26 45428 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "GPSBABEL:"))
27 19 : return true;
28 :
29 45409 : const char *pszGPSBabelDriverName = nullptr;
30 45409 : if (poOpenInfo->fpL == nullptr)
31 42848 : return false;
32 :
33 2561 : if (memcmp(poOpenInfo->pabyHeader, "MsRcd", 5) == 0)
34 0 : pszGPSBabelDriverName = "mapsource";
35 2561 : else if (memcmp(poOpenInfo->pabyHeader, "MsRcf", 5) == 0)
36 0 : pszGPSBabelDriverName = "gdb";
37 2561 : 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 2561 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
45 : "<TrainingCenterDatabase") != nullptr)
46 0 : pszGPSBabelDriverName = "gtrnctr";
47 2561 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
48 2561 : "$GPGSA") != nullptr ||
49 2561 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
50 : "$GPGGA") != nullptr)
51 2 : pszGPSBabelDriverName = "nmea";
52 2559 : else if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader,
53 : "OziExplorer"))
54 0 : pszGPSBabelDriverName = "ozi";
55 2559 : 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 2559 : 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 2559 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
77 2559 : "$PMGNWPL") != nullptr ||
78 2559 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
79 : "$PMGNRTE") != nullptr)
80 0 : pszGPSBabelDriverName = "magellan";
81 5683 : 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 3659 : poOpenInfo->pabyHeader[3] <= 'Z' &&
88 535 : EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "igc"))
89 0 : pszGPSBabelDriverName = "igc";
90 :
91 : static int bGPSBabelFound = -1;
92 2561 : 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 2561 : if (bGPSBabelFound)
112 : {
113 2561 : *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 2561 : return *ppszGSPBabelDriverName != nullptr;
123 : }
124 :
125 45418 : static int OGRGPSBabelDriverIdentify(GDALOpenInfo *poOpenInfo)
126 : {
127 45418 : const char *pszGPSBabelDriverName = nullptr;
128 45418 : return OGRGPSBabelDriverIdentifyInternal(poOpenInfo,
129 45418 : &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 1595 : void RegisterOGRGPSBabel()
195 : {
196 1595 : if (!GDAL_CHECK_VERSION("OGR/GPSBabel driver"))
197 0 : return;
198 :
199 1595 : if (GDALGetDriverByName("GPSBabel") != nullptr)
200 302 : return;
201 :
202 1293 : GDALDriver *poDriver = new GDALDriver();
203 :
204 1293 : poDriver->SetDescription("GPSBabel");
205 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
206 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
207 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GPSBabel");
208 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
209 1293 : "drivers/vector/gpsbabel.html");
210 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "mps gdb osm tcx igc");
211 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
212 :
213 1293 : poDriver->SetMetadataItem(GDAL_DMD_CONNECTION_PREFIX, "GPSBABEL:");
214 :
215 1293 : 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 1293 : "</OpenOptionList>");
222 :
223 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST,
224 : "<CreationOptionList>"
225 : " <Option name='GPSBABEL_DRIVER' type='string' "
226 : "description='Name of the GPSBabel to use'/>"
227 1293 : "</CreationOptionList>");
228 :
229 1293 : poDriver->pfnOpen = OGRGPSBabelDriverOpen;
230 1293 : poDriver->pfnIdentify = OGRGPSBabelDriverIdentify;
231 1293 : poDriver->pfnCreate = OGRGPSBabelDriverCreate;
232 1293 : poDriver->pfnDelete = OGRGPSBabelDriverDelete;
233 :
234 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
235 : }
|