1 : /******************************************************************************
2 : * $Id: ogrgpsbabeldatasource.cpp 23557 2011-12-12 22:08:17Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRGPSBabelDataSource class.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, 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_gpsbabel.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "cpl_error.h"
34 :
35 : #include <string.h>
36 :
37 : CPL_CVSID("$Id: ogrgpsbabeldatasource.cpp 23557 2011-12-12 22:08:17Z rouault $");
38 :
39 : /************************************************************************/
40 : /* OGRGPSBabelDataSource() */
41 : /************************************************************************/
42 :
43 76 : OGRGPSBabelDataSource::OGRGPSBabelDataSource()
44 :
45 : {
46 76 : nLayers = 0;
47 76 : pszName = NULL;
48 76 : pszGPSBabelDriverName = NULL;
49 76 : pszFilename = NULL;
50 76 : poGPXDS = NULL;
51 76 : }
52 :
53 : /************************************************************************/
54 : /* ~OGRGPSBabelDataSource() */
55 : /************************************************************************/
56 :
57 76 : OGRGPSBabelDataSource::~OGRGPSBabelDataSource()
58 :
59 : {
60 76 : CPLFree(pszName);
61 76 : CPLFree(pszGPSBabelDriverName);
62 76 : CPLFree(pszFilename);
63 :
64 76 : if (poGPXDS)
65 2 : OGRDataSource::DestroyDataSource(poGPXDS);
66 :
67 76 : if (osTmpFileName.size() > 0)
68 2 : VSIUnlink(osTmpFileName.c_str());
69 76 : }
70 :
71 : /************************************************************************/
72 : /* GetArgv() */
73 : /************************************************************************/
74 :
75 2 : static char** GetArgv(int bExplicitFeatures, int bWaypoints, int bRoutes,
76 : int bTracks, const char* pszGPSBabelDriverName,
77 : const char* pszFilename)
78 : {
79 2 : char** argv = NULL;
80 2 : argv = CSLAddString(argv, "gpsbabel");
81 2 : if (bExplicitFeatures)
82 : {
83 0 : if (bWaypoints) argv = CSLAddString(argv, "-w");
84 0 : if (bRoutes) argv = CSLAddString(argv, "-r");
85 0 : if (bTracks) argv = CSLAddString(argv, "-t");
86 : }
87 2 : argv = CSLAddString(argv, "-i");
88 2 : argv = CSLAddString(argv, pszGPSBabelDriverName);
89 2 : argv = CSLAddString(argv, "-f");
90 2 : argv = CSLAddString(argv, pszFilename);
91 2 : argv = CSLAddString(argv, "-o");
92 2 : argv = CSLAddString(argv, "gpx,gpxver=1.1");
93 2 : argv = CSLAddString(argv, "-F");
94 2 : argv = CSLAddString(argv, "-");
95 :
96 2 : return argv;
97 : }
98 :
99 : /************************************************************************/
100 : /* IsSpecialFile() */
101 : /************************************************************************/
102 :
103 3 : int OGRGPSBabelDataSource::IsSpecialFile(const char* pszFilename)
104 : {
105 : return (strncmp(pszFilename, "/dev/", 5) == 0 ||
106 : strncmp(pszFilename, "usb:", 4) == 0 ||
107 3 : (strncmp(pszFilename, "COM", 3) == 0 && atoi(pszFilename + 3) > 0));
108 : }
109 :
110 : /************************************************************************/
111 : /* IsValidDriverName() */
112 : /************************************************************************/
113 :
114 2 : int OGRGPSBabelDataSource::IsValidDriverName(const char* pszGPSBabelDriverName)
115 : {
116 : int i;
117 10 : for(i=0;pszGPSBabelDriverName[i] != '\0';i++)
118 : {
119 8 : char ch = pszGPSBabelDriverName[i];
120 8 : if (!((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
121 : (ch >= '0' && ch <= '9') || ch == '_' || ch == '=' || ch == '.' || ch == ','))
122 : {
123 : CPLError(CE_Failure, CPLE_AppDefined,
124 0 : "Invalid GPSBabel driver name");
125 0 : return FALSE;
126 : }
127 : }
128 2 : return TRUE;
129 : }
130 :
131 : /************************************************************************/
132 : /* Open() */
133 : /************************************************************************/
134 :
135 76 : int OGRGPSBabelDataSource::Open( const char * pszDatasourceName, int bUpdateIn)
136 :
137 : {
138 76 : int bExplicitFeatures = FALSE;
139 76 : int bWaypoints = TRUE, bTracks = TRUE, bRoutes = TRUE;
140 76 : if (bUpdateIn)
141 : {
142 : CPLError(CE_Failure, CPLE_NotSupported,
143 0 : "OGR/GPSBabel driver does not support opening a file in update mode");
144 0 : return FALSE;
145 : }
146 :
147 76 : if (!EQUALN(pszDatasourceName, "GPSBABEL:", 9))
148 : {
149 75 : VSILFILE* fp = VSIFOpenL(pszDatasourceName, "rb");
150 75 : if (fp == NULL)
151 36 : return FALSE;
152 :
153 : char szHeader[1024 + 1];
154 39 : memset(szHeader, 0, 1024+1);
155 39 : VSIFReadL(szHeader, 1, 1024, fp);
156 39 : if (memcmp(szHeader, "MsRcd", 5) == 0)
157 0 : pszGPSBabelDriverName = CPLStrdup("mapsource");
158 39 : else if (memcmp(szHeader, "MsRcf", 5) == 0)
159 0 : pszGPSBabelDriverName = CPLStrdup("gdb");
160 39 : else if (strstr(szHeader, "<osm") != NULL)
161 0 : pszGPSBabelDriverName = CPLStrdup("osm");
162 40 : else if (strstr(szHeader, "$GPGSA") != NULL ||
163 : strstr(szHeader, "$GPGGA") != NULL)
164 1 : pszGPSBabelDriverName = CPLStrdup("nmea");
165 38 : else if (EQUALN(szHeader, "OziExplorer",11))
166 0 : pszGPSBabelDriverName = CPLStrdup("ozi");
167 38 : else if (strstr(szHeader, "Grid") && strstr(szHeader, "Datum") && strstr(szHeader, "Header"))
168 0 : pszGPSBabelDriverName = CPLStrdup("garmin_txt");
169 38 : else if (szHeader[0] == 13 && szHeader[10] == 'M' && szHeader[11] == 'S' &&
170 0 : (szHeader[12] >= '0' && szHeader[12] <= '9') &&
171 0 : (szHeader[13] >= '0' && szHeader[13] <= '9') &&
172 0 : szHeader[12] * 10 + szHeader[13] >= 30 &&
173 0 : (szHeader[14] == 1 || szHeader[14] == 2) && szHeader[15] == 0 &&
174 0 : szHeader[16] == 0 && szHeader[17] == 0)
175 0 : pszGPSBabelDriverName = CPLStrdup("mapsend");
176 38 : else if (strstr(szHeader, "$PMGNWPL") != NULL ||
177 : strstr(szHeader, "$PMGNRTE") != NULL)
178 0 : pszGPSBabelDriverName = CPLStrdup("magellan");
179 :
180 39 : VSIFCloseL(fp);
181 :
182 39 : if (pszGPSBabelDriverName == NULL)
183 : {
184 38 : return FALSE;
185 : }
186 :
187 1 : pszFilename = CPLStrdup(pszDatasourceName);
188 : }
189 :
190 2 : pszName = CPLStrdup( pszDatasourceName );
191 :
192 2 : if (pszGPSBabelDriverName == NULL)
193 : {
194 1 : const char* pszSep = strchr(pszDatasourceName + 9, ':');
195 1 : if (pszSep == NULL)
196 : {
197 : CPLError(CE_Failure, CPLE_AppDefined,
198 0 : "Wrong syntax. Expected GPSBabel:driver_name:file_name");
199 0 : return FALSE;
200 : }
201 :
202 1 : pszGPSBabelDriverName = CPLStrdup(pszDatasourceName + 9);
203 1 : *(strchr(pszGPSBabelDriverName, ':')) = '\0';
204 :
205 : /* A bit of validation to avoid command line injection */
206 1 : if (!IsValidDriverName(pszGPSBabelDriverName))
207 0 : return FALSE;
208 :
209 : /* Parse optionnal features= option */
210 1 : if (EQUALN(pszSep+1, "features=", 9))
211 : {
212 0 : const char* pszNextSep = strchr(pszSep+1, ':');
213 0 : if (pszNextSep == NULL)
214 : {
215 : CPLError(CE_Failure, CPLE_AppDefined,
216 0 : "Wrong syntax. Expected GPSBabel:driver_name[,options]*:[features=waypoints,tracks,routes:]file_name");
217 0 : return FALSE;
218 : }
219 :
220 0 : char* pszFeatures = CPLStrdup(pszSep+1+9);
221 0 : *strchr(pszFeatures, ':') = 0;
222 0 : char** papszTokens = CSLTokenizeString(pszFeatures);
223 0 : char** papszIter = papszTokens;
224 0 : int bErr = FALSE;
225 0 : bExplicitFeatures = TRUE;
226 0 : bWaypoints = bTracks = bRoutes = FALSE;
227 0 : while(papszIter && *papszIter)
228 : {
229 0 : if (EQUAL(*papszIter, "waypoints"))
230 0 : bWaypoints = TRUE;
231 0 : else if (EQUAL(*papszIter, "tracks"))
232 0 : bTracks = TRUE;
233 0 : else if (EQUAL(*papszIter, "routes"))
234 0 : bRoutes = TRUE;
235 : else
236 : {
237 0 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong value for 'features' options");
238 0 : bErr = TRUE;
239 : }
240 0 : papszIter ++;
241 : }
242 0 : CSLDestroy(papszTokens);
243 0 : CPLFree(pszFeatures);
244 :
245 0 : if (bErr)
246 0 : return FALSE;
247 :
248 0 : pszSep = pszNextSep;
249 : }
250 :
251 1 : pszFilename = CPLStrdup(pszSep+1);
252 : }
253 :
254 2 : const char* pszOptionUseTempFile = CPLGetConfigOption("USE_TEMPFILE", NULL);
255 2 : if (pszOptionUseTempFile && CSLTestBoolean(pszOptionUseTempFile))
256 0 : osTmpFileName = CPLGenerateTempFilename(NULL);
257 : else
258 2 : osTmpFileName.Printf("/vsimem/ogrgpsbabeldatasource_%p", this);
259 :
260 2 : int nRet = FALSE;
261 2 : if (IsSpecialFile(pszFilename))
262 : {
263 : /* Special file : don't try to open it */
264 : char** argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
265 0 : bTracks, pszGPSBabelDriverName, pszFilename);
266 0 : VSILFILE* tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");
267 0 : nRet = ForkAndPipe(argv, NULL, tmpfp);
268 0 : VSIFCloseL(tmpfp);
269 0 : tmpfp = NULL;
270 0 : CSLDestroy(argv);
271 0 : argv = NULL;
272 : }
273 : else
274 : {
275 2 : VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
276 2 : if (fp == NULL)
277 : {
278 : CPLError(CE_Failure, CPLE_AppDefined,
279 0 : "Cannot open file %s", pszFilename);
280 0 : return FALSE;
281 : }
282 :
283 : char** argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
284 2 : bTracks, pszGPSBabelDriverName, "-");
285 :
286 2 : VSILFILE* tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");
287 :
288 2 : CPLPushErrorHandler(CPLQuietErrorHandler);
289 2 : nRet = ForkAndPipe(argv, fp, tmpfp);
290 2 : CPLPopErrorHandler();
291 :
292 2 : CSLDestroy(argv);
293 2 : argv = NULL;
294 :
295 2 : CPLErr nLastErrorType = CPLGetLastErrorType();
296 2 : int nLastErrorNo = CPLGetLastErrorNo();
297 2 : CPLString osLastErrorMsg = CPLGetLastErrorMsg();
298 :
299 2 : VSIFCloseL(tmpfp);
300 2 : tmpfp = NULL;
301 :
302 2 : VSIFCloseL(fp);
303 2 : fp = NULL;
304 :
305 2 : if (!nRet)
306 : {
307 0 : if (strstr(osLastErrorMsg.c_str(), "This format cannot be used in piped commands") == NULL)
308 : {
309 0 : CPLError(nLastErrorType, nLastErrorNo, "%s", osLastErrorMsg.c_str());
310 : }
311 : else
312 : {
313 : VSIStatBuf sStatBuf;
314 0 : if (VSIStat(pszFilename, &sStatBuf) != 0)
315 : {
316 : CPLError(CE_Failure, CPLE_NotSupported,
317 0 : "Driver %s only supports real (non virtual) files", pszGPSBabelDriverName);
318 0 : return FALSE;
319 : }
320 :
321 : /* Try without piping in */
322 : argv = GetArgv(bExplicitFeatures, bWaypoints, bRoutes,
323 0 : bTracks, pszGPSBabelDriverName, pszFilename);
324 0 : tmpfp = VSIFOpenL(osTmpFileName.c_str(), "wb");
325 0 : nRet = ForkAndPipe(argv, NULL, tmpfp);
326 0 : VSIFCloseL(tmpfp);
327 0 : tmpfp = NULL;
328 :
329 0 : CSLDestroy(argv);
330 0 : argv = NULL;
331 : }
332 0 : }
333 : }
334 :
335 :
336 2 : if (nRet)
337 : {
338 2 : poGPXDS = OGRSFDriverRegistrar::Open(osTmpFileName.c_str());
339 2 : if (poGPXDS)
340 : {
341 : OGRLayer* poLayer;
342 :
343 2 : if (bWaypoints)
344 : {
345 2 : poLayer = poGPXDS->GetLayerByName("waypoints");
346 2 : if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
347 2 : apoLayers[nLayers++] = poLayer;
348 : }
349 :
350 2 : if (bRoutes)
351 : {
352 2 : poLayer = poGPXDS->GetLayerByName("routes");
353 2 : if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
354 0 : apoLayers[nLayers++] = poLayer;
355 2 : poLayer = poGPXDS->GetLayerByName("route_points");
356 2 : if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
357 0 : apoLayers[nLayers++] = poLayer;
358 : }
359 :
360 2 : if (bTracks)
361 : {
362 2 : poLayer = poGPXDS->GetLayerByName("tracks");
363 2 : if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
364 2 : apoLayers[nLayers++] = poLayer;
365 2 : poLayer = poGPXDS->GetLayerByName("track_points");
366 2 : if (poLayer != NULL && poLayer->GetFeatureCount() != 0)
367 0 : apoLayers[nLayers++] = poLayer;
368 : }
369 : }
370 : }
371 :
372 2 : return nLayers > 0;
373 : }
374 :
375 : /************************************************************************/
376 : /* TestCapability() */
377 : /************************************************************************/
378 :
379 0 : int OGRGPSBabelDataSource::TestCapability( const char * pszCap )
380 :
381 : {
382 0 : return FALSE;
383 : }
384 :
385 : /************************************************************************/
386 : /* GetLayer() */
387 : /************************************************************************/
388 :
389 0 : OGRLayer *OGRGPSBabelDataSource::GetLayer( int iLayer )
390 :
391 : {
392 0 : if( iLayer < 0 || iLayer >= nLayers )
393 0 : return NULL;
394 : else
395 0 : return apoLayers[iLayer];
396 : }
|