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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_conv.h"
30 : #include "cpl_spawn.h"
31 :
32 : #include "ogr_gpsbabel.h"
33 :
34 : /************************************************************************/
35 : /* OGRGPSBabelDriverIdentify() */
36 : /************************************************************************/
37 :
38 : static bool
39 42375 : OGRGPSBabelDriverIdentifyInternal(GDALOpenInfo *poOpenInfo,
40 : const char **ppszGSPBabelDriverName)
41 : {
42 42375 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "GPSBABEL:"))
43 19 : return true;
44 :
45 42356 : const char *pszGPSBabelDriverName = nullptr;
46 42356 : if (poOpenInfo->fpL == nullptr)
47 40134 : return false;
48 :
49 2222 : if (memcmp(poOpenInfo->pabyHeader, "MsRcd", 5) == 0)
50 0 : pszGPSBabelDriverName = "mapsource";
51 2222 : else if (memcmp(poOpenInfo->pabyHeader, "MsRcf", 5) == 0)
52 0 : pszGPSBabelDriverName = "gdb";
53 2222 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
54 : "<osm") != nullptr)
55 : {
56 0 : if (GDALGetDriverByName("OSM") != nullptr)
57 0 : return false;
58 0 : pszGPSBabelDriverName = "osm";
59 : }
60 2222 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
61 : "<TrainingCenterDatabase") != nullptr)
62 0 : pszGPSBabelDriverName = "gtrnctr";
63 2222 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
64 2222 : "$GPGSA") != nullptr ||
65 2222 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
66 : "$GPGGA") != nullptr)
67 2 : pszGPSBabelDriverName = "nmea";
68 2220 : else if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader,
69 : "OziExplorer"))
70 0 : pszGPSBabelDriverName = "ozi";
71 2220 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
72 0 : "Grid") &&
73 0 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
74 0 : "Datum") &&
75 0 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
76 : "Header"))
77 0 : pszGPSBabelDriverName = "garmin_txt";
78 2220 : else if (poOpenInfo->pabyHeader[0] == 13 &&
79 0 : poOpenInfo->pabyHeader[10] == 'M' &&
80 0 : poOpenInfo->pabyHeader[11] == 'S' &&
81 0 : (poOpenInfo->pabyHeader[12] >= '0' &&
82 0 : poOpenInfo->pabyHeader[12] <= '9') &&
83 0 : (poOpenInfo->pabyHeader[13] >= '0' &&
84 0 : poOpenInfo->pabyHeader[13] <= '9') &&
85 0 : poOpenInfo->pabyHeader[12] * 10 + poOpenInfo->pabyHeader[13] >=
86 0 : 30 &&
87 0 : (poOpenInfo->pabyHeader[14] == 1 ||
88 0 : poOpenInfo->pabyHeader[14] == 2) &&
89 0 : poOpenInfo->pabyHeader[15] == 0 &&
90 0 : poOpenInfo->pabyHeader[16] == 0 && poOpenInfo->pabyHeader[17] == 0)
91 0 : pszGPSBabelDriverName = "mapsend";
92 2220 : else if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
93 2220 : "$PMGNWPL") != nullptr ||
94 2220 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
95 : "$PMGNRTE") != nullptr)
96 0 : pszGPSBabelDriverName = "magellan";
97 4999 : else if (poOpenInfo->pabyHeader[0] == 'A' &&
98 559 : poOpenInfo->pabyHeader[1] >= 'A' &&
99 559 : poOpenInfo->pabyHeader[1] <= 'Z' &&
100 559 : poOpenInfo->pabyHeader[2] >= 'A' &&
101 559 : poOpenInfo->pabyHeader[2] <= 'Z' &&
102 559 : poOpenInfo->pabyHeader[3] >= 'A' &&
103 3309 : poOpenInfo->pabyHeader[3] <= 'Z' &&
104 530 : EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "igc"))
105 0 : pszGPSBabelDriverName = "igc";
106 :
107 : static int bGPSBabelFound = -1;
108 2222 : if (pszGPSBabelDriverName != nullptr && bGPSBabelFound < 0)
109 : {
110 : #ifndef _WIN32
111 : VSIStatBufL sStat;
112 1 : bGPSBabelFound = VSIStatL("/usr/bin/gpsbabel", &sStat) == 0;
113 1 : if (!bGPSBabelFound)
114 : #endif
115 : {
116 0 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
117 0 : const char *const apszArgs[] = {"gpsbabel", "-V", nullptr};
118 0 : CPLString osTmpFileName("/vsimem/gpsbabel_tmp.tmp");
119 0 : VSILFILE *tmpfp = VSIFOpenL(osTmpFileName, "wb");
120 0 : bGPSBabelFound = CPLSpawn(apszArgs, nullptr, tmpfp, FALSE) == 0;
121 0 : VSIFCloseL(tmpfp);
122 0 : VSIUnlink(osTmpFileName);
123 : }
124 : }
125 :
126 2222 : if (bGPSBabelFound)
127 : {
128 2222 : *ppszGSPBabelDriverName = pszGPSBabelDriverName;
129 : }
130 0 : else if (pszGPSBabelDriverName)
131 : {
132 0 : CPLDebug("GPSBABEL",
133 : "File %s could be recognized by GPSBABEL (sub-driver %s), but "
134 : "binary 'gpsbabel' is missing in the PATH",
135 : poOpenInfo->pszFilename, pszGPSBabelDriverName);
136 : }
137 2222 : return *ppszGSPBabelDriverName != nullptr;
138 : }
139 :
140 42365 : static int OGRGPSBabelDriverIdentify(GDALOpenInfo *poOpenInfo)
141 : {
142 42365 : const char *pszGPSBabelDriverName = nullptr;
143 42365 : return OGRGPSBabelDriverIdentifyInternal(poOpenInfo,
144 42365 : &pszGPSBabelDriverName);
145 : }
146 :
147 : /************************************************************************/
148 : /* Open() */
149 : /************************************************************************/
150 :
151 10 : static GDALDataset *OGRGPSBabelDriverOpen(GDALOpenInfo *poOpenInfo)
152 :
153 : {
154 10 : const char *pszGPSBabelDriverName = nullptr;
155 20 : if (poOpenInfo->eAccess == GA_Update ||
156 10 : !OGRGPSBabelDriverIdentifyInternal(poOpenInfo, &pszGPSBabelDriverName))
157 0 : return nullptr;
158 :
159 10 : OGRGPSBabelDataSource *poDS = new OGRGPSBabelDataSource();
160 :
161 10 : if (!poDS->Open(poOpenInfo->pszFilename, pszGPSBabelDriverName,
162 : poOpenInfo->papszOpenOptions))
163 : {
164 5 : delete poDS;
165 5 : poDS = nullptr;
166 : }
167 :
168 10 : return poDS;
169 : }
170 :
171 : /************************************************************************/
172 : /* Create() */
173 : /************************************************************************/
174 :
175 1 : static GDALDataset *OGRGPSBabelDriverCreate(const char *pszName,
176 : int /* nBands */, int /* nXSize */,
177 : int /* nYSize */,
178 : GDALDataType /* eDT */,
179 : char **papszOptions)
180 : {
181 1 : OGRGPSBabelWriteDataSource *poDS = new OGRGPSBabelWriteDataSource();
182 :
183 1 : if (!poDS->Create(pszName, papszOptions))
184 : {
185 0 : delete poDS;
186 0 : poDS = nullptr;
187 : }
188 :
189 1 : return poDS;
190 : }
191 :
192 : /************************************************************************/
193 : /* Delete() */
194 : /************************************************************************/
195 :
196 1 : static CPLErr OGRGPSBabelDriverDelete(const char *pszFilename)
197 :
198 : {
199 1 : if (VSIUnlink(pszFilename) == 0)
200 0 : return CE_None;
201 :
202 1 : return CE_Failure;
203 : }
204 :
205 : /************************************************************************/
206 : /* RegisterOGRGPSBabel() */
207 : /************************************************************************/
208 :
209 1511 : void RegisterOGRGPSBabel()
210 : {
211 1511 : if (!GDAL_CHECK_VERSION("OGR/GPSBabel driver"))
212 0 : return;
213 :
214 1511 : if (GDALGetDriverByName("GPSBabel") != nullptr)
215 295 : return;
216 :
217 1216 : GDALDriver *poDriver = new GDALDriver();
218 :
219 1216 : poDriver->SetDescription("GPSBabel");
220 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
221 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
222 1216 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GPSBabel");
223 1216 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
224 1216 : "drivers/vector/gpsbabel.html");
225 1216 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "mps gdb osm tcx igc");
226 1216 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
227 :
228 1216 : poDriver->SetMetadataItem(GDAL_DMD_CONNECTION_PREFIX, "GPSBABEL:");
229 :
230 1216 : poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST,
231 : "<OpenOptionList>"
232 : " <Option name='FILENAME' type='string' "
233 : "description='Filename to open'/>"
234 : " <Option name='GPSBABEL_DRIVER' type='string' "
235 : "description='Name of the GPSBabel to use'/>"
236 1216 : "</OpenOptionList>");
237 :
238 1216 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST,
239 : "<CreationOptionList>"
240 : " <Option name='GPSBABEL_DRIVER' type='string' "
241 : "description='Name of the GPSBabel to use'/>"
242 1216 : "</CreationOptionList>");
243 :
244 1216 : poDriver->pfnOpen = OGRGPSBabelDriverOpen;
245 1216 : poDriver->pfnIdentify = OGRGPSBabelDriverIdentify;
246 1216 : poDriver->pfnCreate = OGRGPSBabelDriverCreate;
247 1216 : poDriver->pfnDelete = OGRGPSBabelDriverDelete;
248 :
249 1216 : GetGDALDriverManager()->RegisterDriver(poDriver);
250 : }
|