1 : /******************************************************************************
2 : * $Id: ogrgpxlayer.cpp 17753 2009-10-04 18:41:53Z rouault $
3 : *
4 : * Project: GPX Translator
5 : * Purpose: Implements OGRGPXLayer class.
6 : * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, 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_gpx.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "cpl_minixml.h"
34 : #include "ogr_p.h"
35 :
36 : CPL_CVSID("$Id: ogrgpxlayer.cpp 17753 2009-10-04 18:41:53Z rouault $");
37 :
38 : /************************************************************************/
39 : /* OGRGPXLayer() */
40 : /* */
41 : /* Note that the OGRGPXLayer assumes ownership of the passed */
42 : /* file pointer. */
43 : /************************************************************************/
44 :
45 19 : OGRGPXLayer::OGRGPXLayer( const char* pszFilename,
46 : const char* pszLayerName,
47 : GPXGeometryType gpxGeomType,
48 : OGRGPXDataSource* poDS,
49 19 : int bWriteMode)
50 :
51 : {
52 19 : const char* gpxVersion = poDS->GetVersion();
53 :
54 : int i;
55 :
56 19 : eof = FALSE;
57 19 : nNextFID = 0;
58 :
59 19 : this->poDS = poDS;
60 19 : this->bWriteMode = bWriteMode;
61 19 : this->gpxGeomType = gpxGeomType;
62 :
63 19 : pszElementToScan = pszLayerName;
64 :
65 19 : nMaxLinks = atoi(CPLGetConfigOption("GPX_N_MAX_LINKS", "2"));
66 19 : if (nMaxLinks < 0)
67 0 : nMaxLinks = 2;
68 19 : if (nMaxLinks > 100)
69 0 : nMaxLinks = 100;
70 :
71 19 : nFeatures = 0;
72 :
73 19 : bEleAs25D = CSLTestBoolean(CPLGetConfigOption("GPX_ELE_AS_25D", "NO"));
74 :
75 19 : int bShortNames = CSLTestBoolean(CPLGetConfigOption("GPX_SHORT_NAMES", "NO"));
76 :
77 19 : poFeatureDefn = new OGRFeatureDefn( pszLayerName );
78 19 : poFeatureDefn->Reference();
79 :
80 19 : if (gpxGeomType == GPX_TRACK_POINT)
81 : {
82 : /* Don't move this code. This fields must be number 0, 1 and 2 */
83 : /* in order to make OGRGPXLayer::startElementCbk work */
84 3 : OGRFieldDefn oFieldTrackFID("track_fid", OFTInteger );
85 3 : poFeatureDefn->AddFieldDefn( &oFieldTrackFID );
86 :
87 3 : OGRFieldDefn oFieldTrackSegID((bShortNames) ? "trksegid" : "track_seg_id", OFTInteger );
88 3 : poFeatureDefn->AddFieldDefn( &oFieldTrackSegID );
89 :
90 3 : OGRFieldDefn oFieldTrackSegPointID((bShortNames) ? "trksegptid" : "track_seg_point_id", OFTInteger );
91 3 : poFeatureDefn->AddFieldDefn( &oFieldTrackSegPointID );
92 : }
93 16 : else if (gpxGeomType == GPX_ROUTE_POINT)
94 : {
95 : /* Don't move this code. See above */
96 3 : OGRFieldDefn oFieldRouteFID("route_fid", OFTInteger );
97 3 : poFeatureDefn->AddFieldDefn( &oFieldRouteFID );
98 :
99 3 : OGRFieldDefn oFieldRoutePointID((bShortNames) ? "rteptid" : "route_point_id", OFTInteger );
100 3 : poFeatureDefn->AddFieldDefn( &oFieldRoutePointID );
101 : }
102 :
103 30 : if (gpxGeomType == GPX_WPT ||
104 : gpxGeomType == GPX_TRACK_POINT ||
105 : gpxGeomType == GPX_ROUTE_POINT)
106 : {
107 11 : poFeatureDefn->SetGeomType((bEleAs25D) ? wkbPoint25D : wkbPoint);
108 : /* Position info */
109 :
110 11 : OGRFieldDefn oFieldEle("ele", OFTReal );
111 11 : poFeatureDefn->AddFieldDefn( &oFieldEle );
112 :
113 11 : OGRFieldDefn oFieldTime("time", OFTDateTime );
114 11 : poFeatureDefn->AddFieldDefn( &oFieldTime );
115 :
116 11 : if (gpxGeomType == GPX_TRACK_POINT &&
117 : gpxVersion && strcmp(gpxVersion, "1.0") == 0)
118 : {
119 0 : OGRFieldDefn oFieldCourse("course", OFTReal );
120 0 : poFeatureDefn->AddFieldDefn( &oFieldCourse );
121 :
122 0 : OGRFieldDefn oFieldSpeed("speed", OFTReal );
123 0 : poFeatureDefn->AddFieldDefn( &oFieldSpeed );
124 : }
125 :
126 11 : OGRFieldDefn oFieldMagVar("magvar", OFTReal );
127 11 : poFeatureDefn->AddFieldDefn( &oFieldMagVar );
128 :
129 11 : OGRFieldDefn oFieldGeoidHeight("geoidheight", OFTReal );
130 11 : poFeatureDefn->AddFieldDefn( &oFieldGeoidHeight );
131 :
132 : /* Description info */
133 :
134 11 : OGRFieldDefn oFieldName("name", OFTString );
135 11 : poFeatureDefn->AddFieldDefn( &oFieldName );
136 :
137 11 : OGRFieldDefn oFieldCmt("cmt", OFTString );
138 11 : poFeatureDefn->AddFieldDefn( &oFieldCmt );
139 :
140 11 : OGRFieldDefn oFieldDesc("desc", OFTString );
141 11 : poFeatureDefn->AddFieldDefn( &oFieldDesc );
142 :
143 11 : OGRFieldDefn oFieldSrc("src", OFTString );
144 11 : poFeatureDefn->AddFieldDefn( &oFieldSrc );
145 :
146 11 : if (gpxVersion && strcmp(gpxVersion, "1.0") == 0)
147 : {
148 0 : OGRFieldDefn oFieldUrl("url", OFTString );
149 0 : poFeatureDefn->AddFieldDefn( &oFieldUrl );
150 :
151 0 : OGRFieldDefn oFieldUrlName("urlname", OFTString );
152 0 : poFeatureDefn->AddFieldDefn( &oFieldUrlName );
153 : }
154 : else
155 : {
156 33 : for(i=1;i<=nMaxLinks;i++)
157 : {
158 : char szFieldName[32];
159 22 : sprintf(szFieldName, "link%d_href", i);
160 22 : OGRFieldDefn oFieldLinkHref( szFieldName, OFTString );
161 22 : poFeatureDefn->AddFieldDefn( &oFieldLinkHref );
162 :
163 22 : sprintf(szFieldName, "link%d_text", i);
164 22 : OGRFieldDefn oFieldLinkText( szFieldName, OFTString );
165 22 : poFeatureDefn->AddFieldDefn( &oFieldLinkText );
166 :
167 22 : sprintf(szFieldName, "link%d_type", i);
168 22 : OGRFieldDefn oFieldLinkType( szFieldName, OFTString );
169 22 : poFeatureDefn->AddFieldDefn( &oFieldLinkType );
170 : }
171 : }
172 :
173 11 : OGRFieldDefn oFieldSym("sym", OFTString );
174 11 : poFeatureDefn->AddFieldDefn( &oFieldSym );
175 :
176 11 : OGRFieldDefn oFieldType("type", OFTString );
177 11 : poFeatureDefn->AddFieldDefn( &oFieldType );
178 :
179 : /* Accuracy info */
180 :
181 11 : OGRFieldDefn oFieldFix("fix", OFTString );
182 11 : poFeatureDefn->AddFieldDefn( &oFieldFix );
183 :
184 11 : OGRFieldDefn oFieldSat("sat", OFTInteger );
185 11 : poFeatureDefn->AddFieldDefn( &oFieldSat );
186 :
187 11 : OGRFieldDefn oFieldHdop("hdop", OFTReal );
188 11 : poFeatureDefn->AddFieldDefn( &oFieldHdop );
189 :
190 11 : OGRFieldDefn oFieldVdop("vdop", OFTReal );
191 11 : poFeatureDefn->AddFieldDefn( &oFieldVdop );
192 :
193 11 : OGRFieldDefn oFieldPdop("pdop", OFTReal );
194 11 : poFeatureDefn->AddFieldDefn( &oFieldPdop );
195 :
196 11 : OGRFieldDefn oFieldAgeofgpsdata("ageofdgpsdata", OFTReal );
197 11 : poFeatureDefn->AddFieldDefn( &oFieldAgeofgpsdata );
198 :
199 11 : OGRFieldDefn oFieldDgpsid("dgpsid", OFTInteger );
200 11 : poFeatureDefn->AddFieldDefn( &oFieldDgpsid );
201 : }
202 : else
203 : {
204 8 : if (gpxGeomType == GPX_TRACK)
205 4 : poFeatureDefn->SetGeomType((bEleAs25D) ? wkbMultiLineString25D : wkbMultiLineString);
206 : else
207 4 : poFeatureDefn->SetGeomType((bEleAs25D) ? wkbLineString25D : wkbLineString);
208 :
209 8 : OGRFieldDefn oFieldName("name", OFTString );
210 8 : poFeatureDefn->AddFieldDefn( &oFieldName );
211 :
212 8 : OGRFieldDefn oFieldCmt("cmt", OFTString );
213 8 : poFeatureDefn->AddFieldDefn( &oFieldCmt );
214 :
215 8 : OGRFieldDefn oFieldDesc("desc", OFTString );
216 8 : poFeatureDefn->AddFieldDefn( &oFieldDesc );
217 :
218 8 : OGRFieldDefn oFieldSrc("src", OFTString );
219 8 : poFeatureDefn->AddFieldDefn( &oFieldSrc );
220 :
221 24 : for(i=1;i<=nMaxLinks;i++)
222 : {
223 : char szFieldName[32];
224 16 : sprintf(szFieldName, "link%d_href", i);
225 16 : OGRFieldDefn oFieldLinkHref( szFieldName, OFTString );
226 16 : poFeatureDefn->AddFieldDefn( &oFieldLinkHref );
227 :
228 16 : sprintf(szFieldName, "link%d_text", i);
229 16 : OGRFieldDefn oFieldLinkText( szFieldName, OFTString );
230 16 : poFeatureDefn->AddFieldDefn( &oFieldLinkText );
231 :
232 16 : sprintf(szFieldName, "link%d_type", i);
233 16 : OGRFieldDefn oFieldLinkType( szFieldName, OFTString );
234 16 : poFeatureDefn->AddFieldDefn( &oFieldLinkType );
235 : }
236 :
237 8 : OGRFieldDefn oFieldNumber("number", OFTInteger );
238 8 : poFeatureDefn->AddFieldDefn( &oFieldNumber );
239 :
240 8 : OGRFieldDefn oFieldType("type", OFTString );
241 8 : poFeatureDefn->AddFieldDefn( &oFieldType );
242 : }
243 :
244 : /* Number of 'standard' GPX attributes */
245 19 : nGPXFields = poFeatureDefn->GetFieldCount();
246 :
247 19 : ppoFeatureTab = NULL;
248 19 : nFeatureTabIndex = 0;
249 19 : nFeatureTabLength = 0;
250 19 : pszSubElementName = NULL;
251 19 : pszSubElementValue = NULL;
252 19 : nSubElementValueLen = 0;
253 19 : bStopParsing = FALSE;
254 :
255 : poSRS = new OGRSpatialReference("GEOGCS[\"WGS 84\", "
256 : " DATUM[\"WGS_1984\","
257 : " SPHEROID[\"WGS 84\",6378137,298.257223563,"
258 : " AUTHORITY[\"EPSG\",\"7030\"]],"
259 : " AUTHORITY[\"EPSG\",\"6326\"]],"
260 : " PRIMEM[\"Greenwich\",0,"
261 : " AUTHORITY[\"EPSG\",\"8901\"]],"
262 : " UNIT[\"degree\",0.01745329251994328,"
263 : " AUTHORITY[\"EPSG\",\"9122\"]],"
264 19 : " AUTHORITY[\"EPSG\",\"4326\"]]");
265 :
266 19 : poFeature = NULL;
267 :
268 : #ifdef HAVE_EXPAT
269 19 : oParser = NULL;
270 : #endif
271 :
272 19 : if (bWriteMode == FALSE)
273 : {
274 15 : fpGPX = VSIFOpenL( pszFilename, "r" );
275 15 : if( fpGPX == NULL )
276 : {
277 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s", pszFilename);
278 0 : return;
279 : }
280 :
281 15 : if (poDS->GetUseExtensions() ||
282 : CSLTestBoolean(CPLGetConfigOption("GPX_USE_EXTENSIONS", "FALSE")))
283 : {
284 10 : LoadExtensionsSchema();
285 : }
286 : }
287 : else
288 4 : fpGPX = NULL;
289 :
290 19 : ResetReading();
291 0 : }
292 :
293 : /************************************************************************/
294 : /* ~OGRGPXLayer() */
295 : /************************************************************************/
296 :
297 38 : OGRGPXLayer::~OGRGPXLayer()
298 :
299 : {
300 : #ifdef HAVE_EXPAT
301 19 : if (oParser)
302 15 : XML_ParserFree(oParser);
303 : #endif
304 19 : poFeatureDefn->Release();
305 :
306 19 : if( poSRS != NULL )
307 19 : poSRS->Release();
308 :
309 19 : CPLFree(pszSubElementName);
310 19 : CPLFree(pszSubElementValue);
311 :
312 : int i;
313 24 : for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
314 5 : delete ppoFeatureTab[i];
315 19 : CPLFree(ppoFeatureTab);
316 :
317 19 : if (poFeature)
318 0 : delete poFeature;
319 :
320 19 : if (fpGPX)
321 15 : VSIFCloseL( fpGPX );
322 38 : }
323 :
324 : #ifdef HAVE_EXPAT
325 :
326 1414 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName, const char **ppszAttr)
327 : {
328 1414 : ((OGRGPXLayer*)pUserData)->startElementCbk(pszName, ppszAttr);
329 1414 : }
330 :
331 1414 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
332 : {
333 1414 : ((OGRGPXLayer*)pUserData)->endElementCbk(pszName);
334 1414 : }
335 :
336 3913 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
337 : {
338 3913 : ((OGRGPXLayer*)pUserData)->dataHandlerCbk(data, nLen);
339 3913 : }
340 :
341 : #endif
342 :
343 : /************************************************************************/
344 : /* ResetReading() */
345 : /************************************************************************/
346 :
347 48 : void OGRGPXLayer::ResetReading()
348 :
349 : {
350 48 : eof = FALSE;
351 48 : nNextFID = 0;
352 48 : if (fpGPX)
353 : {
354 44 : VSIFSeekL( fpGPX, 0, SEEK_SET );
355 : #ifdef HAVE_EXPAT
356 44 : if (oParser)
357 29 : XML_ParserFree(oParser);
358 :
359 44 : oParser = OGRCreateExpatXMLParser();
360 44 : XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
361 44 : XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
362 44 : XML_SetUserData(oParser, this);
363 : #endif
364 : }
365 48 : hasFoundLat = FALSE;
366 48 : hasFoundLon = FALSE;
367 48 : inInterestingElement = FALSE;
368 48 : CPLFree(pszSubElementName);
369 48 : pszSubElementName = NULL;
370 48 : CPLFree(pszSubElementValue);
371 48 : pszSubElementValue = NULL;
372 48 : nSubElementValueLen = 0;
373 :
374 : int i;
375 48 : for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
376 0 : delete ppoFeatureTab[i];
377 48 : CPLFree(ppoFeatureTab);
378 48 : nFeatureTabIndex = 0;
379 48 : nFeatureTabLength = 0;
380 48 : ppoFeatureTab = NULL;
381 48 : if (poFeature)
382 0 : delete poFeature;
383 48 : poFeature = NULL;
384 48 : multiLineString = NULL;
385 48 : lineString = NULL;
386 :
387 48 : depthLevel = 0;
388 48 : interestingDepthLevel = 0;
389 :
390 48 : trkFID = trkSegId = trkSegPtId = 0;
391 48 : rteFID = rtePtId = 0;
392 48 : }
393 :
394 : #ifdef HAVE_EXPAT
395 :
396 : /************************************************************************/
397 : /* startElementCbk() */
398 : /************************************************************************/
399 :
400 : /** Replace ':' from XML NS element name by '_' more OGR friendly */
401 48 : static char* OGRGPX_GetOGRCompatibleTagName(const char* pszName)
402 : {
403 48 : char* pszModName = CPLStrdup(pszName);
404 : int i;
405 704 : for(i=0;pszModName[i] != 0;i++)
406 : {
407 656 : if (pszModName[i] == ':')
408 48 : pszModName[i] = '_';
409 : }
410 48 : return pszModName;
411 : }
412 :
413 0 : void OGRGPXLayer::AddStrToSubElementValue(const char* pszStr)
414 : {
415 0 : int len = strlen(pszStr);
416 : char* pszNewSubElementValue = (char*)
417 0 : VSIRealloc(pszSubElementValue, nSubElementValueLen + len + 1);
418 0 : if (pszNewSubElementValue == NULL)
419 : {
420 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
421 0 : XML_StopParser(oParser, XML_FALSE);
422 0 : bStopParsing = TRUE;
423 0 : return;
424 : }
425 0 : pszSubElementValue = pszNewSubElementValue;
426 0 : memcpy(pszSubElementValue + nSubElementValueLen, pszStr, len);
427 0 : nSubElementValueLen += len;
428 : }
429 :
430 1414 : void OGRGPXLayer::startElementCbk(const char *pszName, const char **ppszAttr)
431 : {
432 : int i;
433 :
434 1414 : if (bStopParsing) return;
435 :
436 1414 : nWithoutEventCounter = 0;
437 :
438 1476 : if ((gpxGeomType == GPX_WPT && strcmp(pszName, "wpt") == 0) ||
439 : (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rtept") == 0) ||
440 : (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkpt") == 0))
441 : {
442 62 : interestingDepthLevel = depthLevel;
443 :
444 62 : if (poFeature)
445 0 : delete poFeature;
446 :
447 62 : poFeature = new OGRFeature( poFeatureDefn );
448 62 : inInterestingElement = TRUE;
449 62 : hasFoundLat = FALSE;
450 62 : hasFoundLon = FALSE;
451 62 : inExtensions = FALSE;
452 62 : inLink = FALSE;
453 62 : iCountLink = 0;
454 :
455 186 : for (i = 0; ppszAttr[i]; i += 2)
456 : {
457 124 : if (strcmp(ppszAttr[i], "lat") == 0)
458 : {
459 62 : hasFoundLat = TRUE;
460 62 : latVal = CPLAtof(ppszAttr[i + 1]);
461 : }
462 62 : else if (strcmp(ppszAttr[i], "lon") == 0)
463 : {
464 62 : hasFoundLon = TRUE;
465 62 : lonVal = CPLAtof(ppszAttr[i + 1]);
466 : }
467 : }
468 :
469 62 : if (hasFoundLat && hasFoundLon)
470 : {
471 62 : poFeature->SetFID( nNextFID++ );
472 62 : poFeature->SetGeometryDirectly( new OGRPoint( lonVal, latVal ) );
473 :
474 62 : if (gpxGeomType == GPX_ROUTE_POINT)
475 : {
476 6 : rtePtId++;
477 6 : poFeature->SetField( 0, rteFID-1);
478 6 : poFeature->SetField( 1, rtePtId-1);
479 : }
480 56 : else if (gpxGeomType == GPX_TRACK_POINT)
481 : {
482 8 : trkSegPtId++;
483 :
484 8 : poFeature->SetField( 0, trkFID-1);
485 8 : poFeature->SetField( 1, trkSegId-1);
486 8 : poFeature->SetField( 2, trkSegPtId-1);
487 : }
488 : }
489 : }
490 1361 : else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trk") == 0)
491 : {
492 9 : interestingDepthLevel = depthLevel;
493 :
494 9 : if (poFeature)
495 0 : delete poFeature;
496 9 : inExtensions = FALSE;
497 9 : inLink = FALSE;
498 9 : iCountLink = 0;
499 9 : poFeature = new OGRFeature( poFeatureDefn );
500 9 : inInterestingElement = TRUE;
501 :
502 18 : multiLineString = new OGRMultiLineString ();
503 9 : lineString = NULL;
504 :
505 9 : poFeature->SetFID( nNextFID++ );
506 9 : poFeature->SetGeometryDirectly( multiLineString );
507 : }
508 1349 : else if (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trk") == 0)
509 : {
510 6 : trkFID++;
511 6 : trkSegId = 0;
512 : }
513 1343 : else if (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkseg") == 0)
514 : {
515 6 : trkSegId++;
516 6 : trkSegPtId = 0;
517 : }
518 1337 : else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rte") == 0)
519 : {
520 6 : interestingDepthLevel = depthLevel;
521 :
522 6 : if (poFeature)
523 0 : delete poFeature;
524 :
525 6 : poFeature = new OGRFeature( poFeatureDefn );
526 6 : inInterestingElement = TRUE;
527 6 : inExtensions = FALSE;
528 6 : inLink = FALSE;
529 6 : iCountLink = 0;
530 :
531 12 : lineString = new OGRLineString ();
532 6 : poFeature->SetFID( nNextFID++ );
533 6 : poFeature->SetGeometryDirectly( lineString );
534 : }
535 1329 : else if (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rte") == 0)
536 : {
537 4 : rteFID++;
538 4 : rtePtId = 0;
539 : }
540 1321 : else if (inInterestingElement)
541 : {
542 414 : if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trkseg") == 0 &&
543 : depthLevel == interestingDepthLevel + 1)
544 : {
545 9 : if (multiLineString)
546 : {
547 9 : lineString = new OGRLineString ();
548 9 : multiLineString->addGeometryDirectly( lineString );
549 : }
550 : }
551 408 : else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trkpt") == 0 &&
552 : depthLevel == interestingDepthLevel + 2)
553 : {
554 12 : if (lineString)
555 : {
556 12 : hasFoundLat = FALSE;
557 12 : hasFoundLon = FALSE;
558 36 : for (i = 0; ppszAttr[i]; i += 2)
559 : {
560 24 : if (strcmp(ppszAttr[i], "lat") == 0)
561 : {
562 12 : hasFoundLat = TRUE;
563 12 : latVal = CPLAtof(ppszAttr[i + 1]);
564 : }
565 12 : else if (strcmp(ppszAttr[i], "lon") == 0)
566 : {
567 12 : hasFoundLon = TRUE;
568 12 : lonVal = CPLAtof(ppszAttr[i + 1]);
569 : }
570 : }
571 :
572 12 : if (hasFoundLat && hasFoundLon)
573 : {
574 12 : lineString->addPoint(lonVal, latVal);
575 : }
576 : }
577 : }
578 393 : else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rtept") == 0 &&
579 : depthLevel == interestingDepthLevel + 1)
580 : {
581 9 : if (lineString)
582 : {
583 9 : hasFoundLat = FALSE;
584 9 : hasFoundLon = FALSE;
585 27 : for (i = 0; ppszAttr[i]; i += 2)
586 : {
587 18 : if (strcmp(ppszAttr[i], "lat") == 0)
588 : {
589 9 : hasFoundLat = TRUE;
590 9 : latVal = CPLAtof(ppszAttr[i + 1]);
591 : }
592 9 : else if (strcmp(ppszAttr[i], "lon") == 0)
593 : {
594 9 : hasFoundLon = TRUE;
595 9 : lonVal = CPLAtof(ppszAttr[i + 1]);
596 : }
597 : }
598 :
599 9 : if (hasFoundLat && hasFoundLon)
600 : {
601 9 : lineString->addPoint(lonVal, latVal);
602 : }
603 : }
604 : }
605 375 : else if (bEleAs25D &&
606 : strcmp(pszName, "ele") == 0 &&
607 : lineString != NULL &&
608 : ((gpxGeomType == GPX_ROUTE && depthLevel == interestingDepthLevel + 2) ||
609 : (gpxGeomType == GPX_TRACK && depthLevel == interestingDepthLevel + 3)))
610 : {
611 0 : CPLFree(pszSubElementName);
612 0 : pszSubElementName = CPLStrdup(pszName);
613 : }
614 392 : else if (depthLevel == interestingDepthLevel + 1 &&
615 : strcmp(pszName, "extensions") == 0)
616 : {
617 17 : if (poDS->GetUseExtensions())
618 : {
619 17 : inExtensions = TRUE;
620 : }
621 : }
622 590 : else if (depthLevel == interestingDepthLevel + 1 ||
623 : (inExtensions && depthLevel == interestingDepthLevel + 2) )
624 : {
625 232 : CPLFree(pszSubElementName);
626 232 : pszSubElementName = NULL;
627 232 : iCurrentField = -1;
628 :
629 232 : if (strcmp(pszName, "link") == 0)
630 : {
631 53 : iCountLink++;
632 53 : if (iCountLink <= nMaxLinks)
633 : {
634 42 : if (ppszAttr[0] && ppszAttr[1] &&
635 : strcmp(ppszAttr[0], "href") == 0)
636 : {
637 : char szFieldName[32];
638 42 : sprintf(szFieldName, "link%d_href", iCountLink);
639 42 : iCurrentField = poFeatureDefn->GetFieldIndex(szFieldName);
640 42 : poFeature->SetField( iCurrentField, ppszAttr[1]);
641 : }
642 : }
643 : else
644 : {
645 : static int once = 1;
646 11 : if (once)
647 : {
648 1 : once = 0;
649 : CPLError(CE_Warning, CPLE_AppDefined,
650 : "GPX driver only reads %d links per element. Others will be ignored. "
651 : "This can be changed with the GPX_N_MAX_LINKS environment variable",
652 1 : nMaxLinks);
653 : }
654 : }
655 53 : inLink = TRUE;
656 53 : iCurrentField = -1;
657 : }
658 : else
659 : {
660 1162 : for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
661 : {
662 : int bMatch;
663 1162 : if (iField >= nGPXFields)
664 : {
665 36 : char* pszCompatibleName = OGRGPX_GetOGRCompatibleTagName(pszName);
666 : bMatch = (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
667 36 : pszCompatibleName ) == 0);
668 36 : CPLFree(pszCompatibleName);
669 : }
670 : else
671 : bMatch = (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
672 1126 : pszName ) == 0);
673 :
674 1162 : if (bMatch)
675 : {
676 179 : iCurrentField = iField;
677 179 : pszSubElementName = CPLStrdup(pszName);
678 179 : break;
679 : }
680 : }
681 : }
682 : }
683 232 : else if (depthLevel == interestingDepthLevel + 2 && inLink)
684 : {
685 : char szFieldName[32];
686 106 : CPLFree(pszSubElementName);
687 106 : pszSubElementName = NULL;
688 106 : iCurrentField = -1;
689 106 : if (iCountLink <= nMaxLinks)
690 : {
691 84 : if (strcmp(pszName, "type") == 0)
692 : {
693 42 : sprintf(szFieldName, "link%d_type", iCountLink);
694 42 : iCurrentField = poFeatureDefn->GetFieldIndex(szFieldName);
695 42 : pszSubElementName = CPLStrdup(pszName);
696 : }
697 42 : else if (strcmp(pszName, "text") == 0)
698 : {
699 42 : sprintf(szFieldName, "link%d_text", iCountLink);
700 42 : iCurrentField = poFeatureDefn->GetFieldIndex(szFieldName);
701 42 : pszSubElementName = CPLStrdup(pszName);
702 : }
703 : }
704 : }
705 20 : else if (inExtensions && depthLevel > interestingDepthLevel + 2)
706 : {
707 : AddStrToSubElementValue(
708 0 : (ppszAttr[0] == NULL) ? CPLSPrintf("<%s>", pszName) :
709 0 : CPLSPrintf("<%s ", pszName));
710 : int i;
711 0 : for (i = 0; ppszAttr[i]; i += 2)
712 : {
713 : AddStrToSubElementValue(
714 0 : CPLSPrintf("%s=\"%s\" ", ppszAttr[i], ppszAttr[i + 1]));
715 : }
716 0 : if (ppszAttr[0] != NULL)
717 : {
718 0 : AddStrToSubElementValue(">");
719 : }
720 : }
721 : }
722 :
723 1414 : depthLevel++;
724 : }
725 :
726 : /************************************************************************/
727 : /* endElementCbk() */
728 : /************************************************************************/
729 :
730 1414 : void OGRGPXLayer::endElementCbk(const char *pszName)
731 : {
732 1414 : if (bStopParsing) return;
733 :
734 1414 : nWithoutEventCounter = 0;
735 :
736 1414 : depthLevel--;
737 :
738 1414 : if (inInterestingElement)
739 : {
740 544 : if ((gpxGeomType == GPX_WPT && strcmp(pszName, "wpt") == 0) ||
741 : (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rtept") == 0) ||
742 : (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkpt") == 0))
743 : {
744 62 : int bIsValid = (hasFoundLat && hasFoundLon);
745 62 : inInterestingElement = FALSE;
746 :
747 62 : if( bIsValid
748 : && (m_poFilterGeom == NULL
749 : || FilterGeometry( poFeature->GetGeometryRef() ) )
750 : && (m_poAttrQuery == NULL
751 : || m_poAttrQuery->Evaluate( poFeature )) )
752 : {
753 62 : if( poFeature->GetGeometryRef() != NULL )
754 : {
755 62 : poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
756 :
757 62 : if (bEleAs25D)
758 : {
759 0 : for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
760 : {
761 0 : if (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), "ele" ) == 0)
762 : {
763 0 : if( poFeature->IsFieldSet( iField ) )
764 : {
765 0 : double val = poFeature->GetFieldAsDouble( iField);
766 0 : ((OGRPoint*)poFeature->GetGeometryRef())->setZ(val);
767 0 : poFeature->GetGeometryRef()->setCoordinateDimension(3);
768 : }
769 0 : break;
770 : }
771 : }
772 : }
773 : }
774 :
775 : ppoFeatureTab = (OGRFeature**)
776 : CPLRealloc(ppoFeatureTab,
777 62 : sizeof(OGRFeature*) * (nFeatureTabLength + 1));
778 62 : ppoFeatureTab[nFeatureTabLength] = poFeature;
779 62 : nFeatureTabLength++;
780 : }
781 : else
782 : {
783 0 : delete poFeature;
784 : }
785 62 : poFeature = NULL;
786 : }
787 429 : else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trk") == 0)
788 : {
789 9 : inInterestingElement = FALSE;
790 9 : if( (m_poFilterGeom == NULL
791 : || FilterGeometry( poFeature->GetGeometryRef() ) )
792 : && (m_poAttrQuery == NULL
793 : || m_poAttrQuery->Evaluate( poFeature )) )
794 : {
795 9 : if( poFeature->GetGeometryRef() != NULL )
796 : {
797 9 : poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
798 : }
799 :
800 : ppoFeatureTab = (OGRFeature**)
801 : CPLRealloc(ppoFeatureTab,
802 9 : sizeof(OGRFeature*) * (nFeatureTabLength + 1));
803 9 : ppoFeatureTab[nFeatureTabLength] = poFeature;
804 9 : nFeatureTabLength++;
805 : }
806 : else
807 : {
808 0 : delete poFeature;
809 : }
810 9 : poFeature = NULL;
811 9 : multiLineString = NULL;
812 9 : lineString = NULL;
813 : }
814 420 : else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trkseg") == 0 &&
815 : depthLevel == interestingDepthLevel + 1)
816 : {
817 9 : lineString = NULL;
818 : }
819 408 : else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rte") == 0)
820 : {
821 6 : inInterestingElement = FALSE;
822 6 : if( (m_poFilterGeom == NULL
823 : || FilterGeometry( poFeature->GetGeometryRef() ) )
824 : && (m_poAttrQuery == NULL
825 : || m_poAttrQuery->Evaluate( poFeature )) )
826 : {
827 6 : if( poFeature->GetGeometryRef() != NULL )
828 : {
829 6 : poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
830 : }
831 :
832 : ppoFeatureTab = (OGRFeature**)
833 : CPLRealloc(ppoFeatureTab,
834 6 : sizeof(OGRFeature*) * (nFeatureTabLength + 1));
835 6 : ppoFeatureTab[nFeatureTabLength] = poFeature;
836 6 : nFeatureTabLength++;
837 : }
838 : else
839 : {
840 0 : delete poFeature;
841 : }
842 6 : poFeature = NULL;
843 6 : lineString = NULL;
844 : }
845 396 : else if (bEleAs25D &&
846 : strcmp(pszName, "ele") == 0 &&
847 : lineString != NULL &&
848 : ((gpxGeomType == GPX_ROUTE && depthLevel == interestingDepthLevel + 2) ||
849 : (gpxGeomType == GPX_TRACK && depthLevel == interestingDepthLevel + 3)))
850 : {
851 0 : poFeature->GetGeometryRef()->setCoordinateDimension(3);
852 :
853 0 : if (nSubElementValueLen)
854 : {
855 0 : pszSubElementValue[nSubElementValueLen] = 0;
856 :
857 0 : double val = CPLAtof(pszSubElementValue);
858 0 : int i = lineString->getNumPoints() - 1;
859 0 : if (i >= 0)
860 0 : lineString->setPoint(i, lineString->getX(i), lineString->getY(i), val);
861 : }
862 :
863 0 : CPLFree(pszSubElementName);
864 0 : pszSubElementName = NULL;
865 0 : CPLFree(pszSubElementValue);
866 0 : pszSubElementValue = NULL;
867 0 : nSubElementValueLen = 0;
868 : }
869 413 : else if (depthLevel == interestingDepthLevel + 1 &&
870 : strcmp(pszName, "extensions") == 0)
871 : {
872 17 : inExtensions = FALSE;
873 : }
874 558 : else if ((depthLevel == interestingDepthLevel + 1 ||
875 : (inExtensions && depthLevel == interestingDepthLevel + 2) ) &&
876 : pszSubElementName && strcmp(pszName, pszSubElementName) == 0)
877 : {
878 179 : if (poFeature && pszSubElementValue && nSubElementValueLen)
879 : {
880 176 : pszSubElementValue[nSubElementValueLen] = 0;
881 176 : if (strcmp(pszSubElementName, "time") == 0)
882 : {
883 : int year, month, day, hour, minute, TZ;
884 : float second;
885 23 : if (OGRParseXMLDateTime(pszSubElementValue, &year, &month, &day, &hour, &minute, &second, &TZ))
886 : {
887 23 : poFeature->SetField(iCurrentField, year, month, day, hour, minute, (int)(second + .5), TZ);
888 : }
889 : else
890 : {
891 : CPLError(CE_Warning, CPLE_AppDefined,
892 0 : "Could not parse %s as a valid dateTime", pszSubElementValue);
893 : }
894 : }
895 : else
896 : {
897 153 : poFeature->SetField( iCurrentField, pszSubElementValue);
898 : }
899 : }
900 179 : if (strcmp(pszName, "link") == 0)
901 0 : inLink = FALSE;
902 :
903 179 : CPLFree(pszSubElementName);
904 179 : pszSubElementName = NULL;
905 179 : CPLFree(pszSubElementValue);
906 179 : pszSubElementValue = NULL;
907 179 : nSubElementValueLen = 0;
908 : }
909 306 : else if (inLink && depthLevel == interestingDepthLevel + 2)
910 : {
911 106 : if (iCurrentField != -1 && pszSubElementName &&
912 : strcmp(pszName, pszSubElementName) == 0 && poFeature && pszSubElementValue && nSubElementValueLen)
913 : {
914 84 : pszSubElementValue[nSubElementValueLen] = 0;
915 84 : poFeature->SetField( iCurrentField, pszSubElementValue);
916 : }
917 :
918 106 : CPLFree(pszSubElementName);
919 106 : pszSubElementName = NULL;
920 106 : CPLFree(pszSubElementValue);
921 106 : pszSubElementValue = NULL;
922 106 : nSubElementValueLen = 0;
923 : }
924 94 : else if (inExtensions && depthLevel > interestingDepthLevel + 2)
925 : {
926 0 : AddStrToSubElementValue(CPLSPrintf("</%s>", pszName));
927 : }
928 : }
929 : }
930 :
931 : /************************************************************************/
932 : /* dataHandlerCbk() */
933 : /************************************************************************/
934 :
935 3913 : void OGRGPXLayer::dataHandlerCbk(const char *data, int nLen)
936 : {
937 3913 : if (bStopParsing) return;
938 :
939 3913 : nDataHandlerCounter ++;
940 3913 : if (nDataHandlerCounter >= BUFSIZ)
941 : {
942 0 : CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
943 0 : XML_StopParser(oParser, XML_FALSE);
944 0 : bStopParsing = TRUE;
945 0 : return;
946 : }
947 :
948 3913 : nWithoutEventCounter = 0;
949 :
950 3913 : if (pszSubElementName)
951 : {
952 260 : if (inExtensions && depthLevel > interestingDepthLevel + 2)
953 : {
954 15 : if (data[0] == '\n')
955 0 : return;
956 : }
957 260 : char* pszNewSubElementValue = (char*) VSIRealloc(pszSubElementValue, nSubElementValueLen + nLen + 1);
958 260 : if (pszNewSubElementValue == NULL)
959 : {
960 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
961 0 : XML_StopParser(oParser, XML_FALSE);
962 0 : bStopParsing = TRUE;
963 0 : return;
964 : }
965 260 : pszSubElementValue = pszNewSubElementValue;
966 260 : memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
967 260 : nSubElementValueLen += nLen;
968 260 : if (nSubElementValueLen > 100000)
969 : {
970 : CPLError(CE_Failure, CPLE_AppDefined,
971 0 : "Too much data inside one element. File probably corrupted");
972 0 : XML_StopParser(oParser, XML_FALSE);
973 0 : bStopParsing = TRUE;
974 : }
975 : }
976 : }
977 : #endif
978 :
979 : /************************************************************************/
980 : /* GetNextFeature() */
981 : /************************************************************************/
982 :
983 98 : OGRFeature *OGRGPXLayer::GetNextFeature()
984 : {
985 98 : if (bWriteMode)
986 : {
987 : CPLError(CE_Failure, CPLE_NotSupported,
988 0 : "Cannot read features when writing a GPX file");
989 0 : return NULL;
990 : }
991 :
992 98 : if (fpGPX == NULL)
993 0 : return NULL;
994 :
995 98 : if (bStopParsing)
996 0 : return NULL;
997 :
998 : #ifdef HAVE_EXPAT
999 98 : if (nFeatureTabIndex < nFeatureTabLength)
1000 : {
1001 38 : return ppoFeatureTab[nFeatureTabIndex++];
1002 : }
1003 :
1004 60 : if (VSIFEofL(fpGPX))
1005 26 : return NULL;
1006 :
1007 : char aBuf[BUFSIZ];
1008 :
1009 34 : CPLFree(ppoFeatureTab);
1010 34 : ppoFeatureTab = NULL;
1011 34 : nFeatureTabLength = 0;
1012 34 : nFeatureTabIndex = 0;
1013 34 : nWithoutEventCounter = 0;
1014 :
1015 : int nDone;
1016 34 : do
1017 : {
1018 34 : nDataHandlerCounter = 0;
1019 34 : unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGPX );
1020 34 : nDone = VSIFEofL(fpGPX);
1021 34 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
1022 : {
1023 : CPLError(CE_Failure, CPLE_AppDefined,
1024 : "XML parsing of GPX file failed : %s at line %d, column %d",
1025 : XML_ErrorString(XML_GetErrorCode(oParser)),
1026 : (int)XML_GetCurrentLineNumber(oParser),
1027 0 : (int)XML_GetCurrentColumnNumber(oParser));
1028 0 : bStopParsing = TRUE;
1029 0 : break;
1030 : }
1031 34 : nWithoutEventCounter ++;
1032 : } while (!nDone && nFeatureTabLength == 0 && !bStopParsing && nWithoutEventCounter < 10);
1033 :
1034 34 : if (nWithoutEventCounter == 10)
1035 : {
1036 : CPLError(CE_Failure, CPLE_AppDefined,
1037 0 : "Too much data inside one element. File probably corrupted");
1038 0 : bStopParsing = TRUE;
1039 : }
1040 :
1041 34 : return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : NULL;
1042 : #else
1043 : return NULL;
1044 : #endif
1045 : }
1046 :
1047 : /************************************************************************/
1048 : /* GetSpatialRef() */
1049 : /************************************************************************/
1050 :
1051 0 : OGRSpatialReference *OGRGPXLayer::GetSpatialRef()
1052 :
1053 : {
1054 0 : return poSRS;
1055 : }
1056 :
1057 : /************************************************************************/
1058 : /* OGRGPX_GetXMLCompatibleTagName() */
1059 : /************************************************************************/
1060 :
1061 6 : static char* OGRGPX_GetXMLCompatibleTagName(const char* pszExtensionsNS,
1062 : const char* pszName)
1063 : {
1064 : /* Skip "ogr_" for example if NS is "ogr". Usefull for GPX -> GPX roundtrip */
1065 6 : if (strncmp(pszName, pszExtensionsNS, strlen(pszExtensionsNS)) == 0 &&
1066 0 : pszName[strlen(pszExtensionsNS)] == '_')
1067 : {
1068 0 : pszName += strlen(pszExtensionsNS) + 1;
1069 : }
1070 :
1071 6 : char* pszModName = CPLStrdup(pszName);
1072 : int i;
1073 66 : for(i=0;pszModName[i] != 0;i++)
1074 : {
1075 60 : if (pszModName[i] == ' ')
1076 6 : pszModName[i] = '_';
1077 : }
1078 6 : return pszModName;
1079 : }
1080 :
1081 : /************************************************************************/
1082 : /* OGRGPX_GetUTF8String() */
1083 : /************************************************************************/
1084 :
1085 0 : static char* OGRGPX_GetUTF8String(const char* pszString)
1086 : {
1087 : char *pszEscaped;
1088 0 : if (!CPLIsUTF8(pszString, -1) &&
1089 : CSLTestBoolean(CPLGetConfigOption("OGR_FORCE_ASCII", "YES")))
1090 : {
1091 : static int bFirstTime = TRUE;
1092 0 : if (bFirstTime)
1093 : {
1094 0 : bFirstTime = FALSE;
1095 : CPLError(CE_Warning, CPLE_AppDefined,
1096 : "%s is not a valid UTF-8 string. Forcing it to ASCII.\n"
1097 : "If you still want the original string and change the XML file encoding\n"
1098 : "afterwards, you can define OGR_FORCE_ASCII=NO as configuration option.\n"
1099 0 : "This warning won't be issued anymore", pszString);
1100 : }
1101 : else
1102 : {
1103 : CPLDebug("OGR", "%s is not a valid UTF-8 string. Forcing it to ASCII",
1104 0 : pszString);
1105 : }
1106 0 : pszEscaped = CPLForceToASCII(pszString, -1, '?');
1107 : }
1108 : else
1109 0 : pszEscaped = CPLStrdup(pszString);
1110 :
1111 0 : return pszEscaped;
1112 : }
1113 :
1114 : /************************************************************************/
1115 : /* OGRGPX_WriteXMLExtension() */
1116 : /************************************************************************/
1117 :
1118 0 : static int OGRGPX_WriteXMLExtension(FILE* fp,
1119 : const char* pszTagName,
1120 : const char* pszContent)
1121 : {
1122 0 : CPLXMLNode* poXML = CPLParseXMLString(pszContent);
1123 0 : if (poXML)
1124 : {
1125 : char* pszTagNameWithNS;
1126 0 : const char* pszXMLNS = NULL;
1127 0 : const char* pszUnderscore = strchr(pszTagName, '_');
1128 0 : pszTagNameWithNS = CPLStrdup(pszTagName);
1129 0 : if (pszUnderscore)
1130 0 : pszTagNameWithNS[pszUnderscore - pszTagName] = ':';
1131 :
1132 : /* If we detect a Garmin GPX extension, add its xmlns */
1133 0 : if (strcmp(pszTagName, "gpxx_WaypointExtension") == 0)
1134 0 : pszXMLNS = " xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\"";
1135 :
1136 : /* Don't XML escape here */
1137 0 : char *pszUTF8 = OGRGPX_GetUTF8String( pszContent );
1138 : VSIFPrintf(fp, " <%s%s>%s</%s>\n",
1139 0 : pszTagNameWithNS, (pszXMLNS) ? pszXMLNS : "", pszUTF8, pszTagNameWithNS);
1140 0 : CPLFree(pszUTF8);
1141 :
1142 0 : CPLFree(pszTagNameWithNS);
1143 0 : CPLDestroyXMLNode(poXML);
1144 :
1145 0 : return TRUE;
1146 : }
1147 :
1148 0 : return FALSE;
1149 : }
1150 :
1151 : /************************************************************************/
1152 : /* WriteFeatureAttributes() */
1153 : /************************************************************************/
1154 :
1155 9 : void OGRGPXLayer::WriteFeatureAttributes( OGRFeature *poFeature )
1156 : {
1157 9 : FILE* fp = poDS->GetOutputFP();
1158 : int i;
1159 :
1160 : /* Begin with standard GPX fields */
1161 161 : for(i=0;i<nGPXFields;i++)
1162 : {
1163 152 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
1164 152 : if( poFeature->IsFieldSet( i ) )
1165 : {
1166 17 : const char* pszName = poFieldDefn->GetNameRef();
1167 17 : if (strcmp(pszName, "time") == 0)
1168 : {
1169 : int year, month, day, hour, minute, second, TZFlag;
1170 1 : if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
1171 : &hour, &minute, &second, &TZFlag))
1172 : {
1173 1 : char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
1174 1 : VSIFPrintf(fp, " <time>%s</time>\n", pszDate);
1175 1 : CPLFree(pszDate);
1176 : }
1177 : }
1178 16 : else if (strncmp(pszName, "link", 4) == 0)
1179 : {
1180 6 : if (strstr(pszName, "href"))
1181 : {
1182 2 : VSIFPrintf(fp, " <link href=\"%s\">", poFeature->GetFieldAsString( i ));
1183 2 : if( poFeature->IsFieldSet( i + 1 ) )
1184 2 : VSIFPrintf(fp, "<text>%s</text>", poFeature->GetFieldAsString( i + 1 ));
1185 2 : if( poFeature->IsFieldSet( i + 2 ) )
1186 2 : VSIFPrintf(fp, "<type>%s</type>", poFeature->GetFieldAsString( i + 2 ));
1187 2 : VSIFPrintf(fp, "</link>\n");
1188 : }
1189 : }
1190 : else
1191 : {
1192 : char* pszValue =
1193 10 : OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
1194 : VSIFPrintf(fp, " <%s>%s</%s>\n",
1195 10 : pszName, pszValue, pszName);
1196 10 : CPLFree(pszValue);
1197 : }
1198 : }
1199 : }
1200 :
1201 : /* Write "extra" fields within the <extensions> tag */
1202 9 : int n = poFeatureDefn->GetFieldCount();
1203 9 : if (i < n)
1204 : {
1205 2 : const char* pszExtensionsNS = poDS->GetExtensionsNS();
1206 2 : VSIFPrintf(fp, " <extensions>\n");
1207 8 : for(;i<n;i++)
1208 : {
1209 6 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
1210 6 : if( poFeature->IsFieldSet( i ) )
1211 : {
1212 : char* compatibleName =
1213 6 : OGRGPX_GetXMLCompatibleTagName(pszExtensionsNS, poFieldDefn->GetNameRef());
1214 6 : const char *pszRaw = poFeature->GetFieldAsString( i );
1215 :
1216 : /* Try to detect XML content */
1217 6 : if (pszRaw[0] == '<' && pszRaw[strlen(pszRaw) - 1] == '>')
1218 : {
1219 0 : if (OGRGPX_WriteXMLExtension(fp, compatibleName, pszRaw))
1220 0 : continue;
1221 : }
1222 :
1223 : /* Try to detect XML escaped content */
1224 6 : else if (strncmp(pszRaw, "<", 4) == 0 &&
1225 : strncmp(pszRaw + strlen(pszRaw) - 4, ">", 4) == 0)
1226 : {
1227 0 : char* pszUnescapedContent = CPLUnescapeString( pszRaw, NULL, CPLES_XML );
1228 :
1229 0 : if (OGRGPX_WriteXMLExtension(fp, compatibleName, pszUnescapedContent))
1230 : {
1231 0 : CPLFree(pszUnescapedContent);
1232 0 : continue;
1233 : }
1234 :
1235 0 : CPLFree(pszUnescapedContent);
1236 : }
1237 :
1238 : /* Remove leading spaces for a numeric field */
1239 6 : if (poFieldDefn->GetType() == OFTInteger || poFieldDefn->GetType() == OFTReal)
1240 : {
1241 0 : while( *pszRaw == ' ' )
1242 0 : pszRaw++;
1243 : }
1244 :
1245 6 : char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
1246 : VSIFPrintf(fp, " <%s:%s>%s</%s:%s>\n",
1247 : pszExtensionsNS,
1248 : compatibleName,
1249 : pszEscaped,
1250 : pszExtensionsNS,
1251 6 : compatibleName);
1252 6 : CPLFree(compatibleName);
1253 6 : CPLFree(pszEscaped);
1254 : }
1255 : }
1256 2 : VSIFPrintf(fp, " </extensions>\n");
1257 : }
1258 9 : }
1259 :
1260 : /************************************************************************/
1261 : /* CheckAndFixCoordinatesValidity() */
1262 : /************************************************************************/
1263 :
1264 11 : OGRErr OGRGPXLayer::CheckAndFixCoordinatesValidity( double* pdfLatitude, double* pdfLongitude )
1265 : {
1266 11 : if (pdfLatitude != NULL && (*pdfLatitude < -90 || *pdfLatitude > 90))
1267 : {
1268 : static int bFirstWarning = TRUE;
1269 0 : if (bFirstWarning)
1270 : {
1271 : CPLError(CE_Failure, CPLE_AppDefined,
1272 : "Latitude %f is invalid. Valid range is [-90,90]. This warning will not be issued any more",
1273 0 : *pdfLatitude);
1274 0 : bFirstWarning = FALSE;
1275 : }
1276 0 : return CE_Failure;
1277 : }
1278 :
1279 11 : if (pdfLongitude != NULL && (*pdfLongitude < -180 || *pdfLongitude > 180))
1280 : {
1281 : static int bFirstWarning = TRUE;
1282 0 : if (bFirstWarning)
1283 : {
1284 : CPLError(CE_Warning, CPLE_AppDefined,
1285 : "Longitude %f has been modified to fit into range [-180,180]. This warning will not be issued any more",
1286 0 : *pdfLongitude);
1287 0 : bFirstWarning = FALSE;
1288 : }
1289 :
1290 0 : if (*pdfLongitude > 180)
1291 0 : *pdfLongitude -= ((int) ((*pdfLongitude+180)/360)*360);
1292 0 : else if (*pdfLongitude < -180)
1293 0 : *pdfLongitude += ((int) (180 - *pdfLongitude)/360)*360;
1294 :
1295 0 : return CE_None;
1296 : }
1297 :
1298 11 : return CE_None;
1299 : }
1300 :
1301 : /************************************************************************/
1302 : /* CreateFeature() */
1303 : /************************************************************************/
1304 :
1305 9 : OGRErr OGRGPXLayer::CreateFeature( OGRFeature *poFeature )
1306 :
1307 : {
1308 9 : FILE* fp = poDS->GetOutputFP();
1309 9 : if (fp == NULL)
1310 0 : return CE_Failure;
1311 :
1312 9 : OGRGeometry *poGeom = poFeature->GetGeometryRef();
1313 :
1314 9 : if (gpxGeomType == GPX_WPT)
1315 : {
1316 4 : if (poDS->GetLastGPXGeomTypeWritten() == GPX_ROUTE)
1317 : {
1318 : CPLError( CE_Failure, CPLE_NotSupported,
1319 0 : "Cannot write a 'wpt' element after a 'rte' element.\n");
1320 0 : return OGRERR_FAILURE;
1321 : }
1322 : else
1323 4 : if (poDS->GetLastGPXGeomTypeWritten() == GPX_TRACK)
1324 : {
1325 : CPLError( CE_Failure, CPLE_NotSupported,
1326 0 : "Cannot write a 'wpt' element after a 'trk' element.\n");
1327 0 : return OGRERR_FAILURE;
1328 : }
1329 :
1330 4 : poDS->SetLastGPXGeomTypeWritten(gpxGeomType);
1331 :
1332 4 : if ( poGeom == NULL )
1333 : {
1334 : CPLError( CE_Failure, CPLE_AppDefined,
1335 0 : "Features without geometry not supported by GPX writer in waypoints layer." );
1336 0 : return OGRERR_FAILURE;
1337 : }
1338 :
1339 4 : switch( poGeom->getGeometryType() )
1340 : {
1341 : case wkbPoint:
1342 : case wkbPoint25D:
1343 : {
1344 4 : OGRPoint* point = (OGRPoint*)poGeom;
1345 4 : double lat = point->getY();
1346 4 : double lon = point->getX();
1347 4 : CheckAndFixCoordinatesValidity(&lat, &lon);
1348 4 : poDS->AddCoord(lon, lat);
1349 4 : VSIFPrintf(fp, "<wpt lat=\"%.15f\" lon=\"%.15f\">\n", lat, lon);
1350 4 : WriteFeatureAttributes(poFeature);
1351 4 : VSIFPrintf(fp, "</wpt>\n");
1352 : break;
1353 : }
1354 :
1355 : default:
1356 : {
1357 : CPLError( CE_Failure, CPLE_NotSupported,
1358 : "Geometry type of `%s' not supported fort 'wpt' element.\n",
1359 0 : OGRGeometryTypeToName(poGeom->getGeometryType()) );
1360 0 : return OGRERR_FAILURE;
1361 : }
1362 : }
1363 : }
1364 5 : else if (gpxGeomType == GPX_ROUTE)
1365 : {
1366 2 : if (poDS->GetLastGPXGeomTypeWritten() == GPX_TRACK)
1367 : {
1368 : CPLError( CE_Failure, CPLE_NotSupported,
1369 0 : "Cannot write a 'rte' element after a 'trk' element.\n");
1370 0 : return OGRERR_FAILURE;
1371 : }
1372 :
1373 2 : poDS->SetLastGPXGeomTypeWritten(gpxGeomType);
1374 :
1375 2 : OGRLineString* line = NULL;
1376 :
1377 2 : if ( poGeom == NULL )
1378 : {
1379 0 : VSIFPrintf(fp, "<rte>\n");
1380 0 : WriteFeatureAttributes(poFeature);
1381 0 : VSIFPrintf(fp, "</rte>\n");
1382 0 : return OGRERR_NONE;
1383 : }
1384 :
1385 2 : switch( poGeom->getGeometryType() )
1386 : {
1387 : case wkbLineString:
1388 : case wkbLineString25D:
1389 : {
1390 2 : line = (OGRLineString*)poGeom;
1391 2 : break;
1392 : }
1393 :
1394 : case wkbMultiLineString:
1395 : case wkbMultiLineString25D:
1396 : {
1397 0 : int nGeometries = ((OGRGeometryCollection*)poGeom)->getNumGeometries ();
1398 0 : if (nGeometries == 0)
1399 : {
1400 0 : line = NULL;
1401 : }
1402 0 : else if (nGeometries == 1)
1403 : {
1404 0 : line = (OGRLineString*) ( ((OGRGeometryCollection*)poGeom)->getGeometryRef(0) );
1405 : }
1406 : else
1407 : {
1408 : CPLError( CE_Failure, CPLE_NotSupported,
1409 0 : "Multiline with more than one line is not supported for 'rte' element.\n");
1410 0 : return OGRERR_FAILURE;
1411 : }
1412 0 : break;
1413 : }
1414 :
1415 : default:
1416 : {
1417 : CPLError( CE_Failure, CPLE_NotSupported,
1418 : "Geometry type of `%s' not supported for 'rte' element.\n",
1419 0 : OGRGeometryTypeToName(poGeom->getGeometryType()) );
1420 0 : return OGRERR_FAILURE;
1421 : }
1422 : }
1423 :
1424 2 : int n = (line) ? line->getNumPoints() : 0;
1425 : int i;
1426 2 : VSIFPrintf(fp, "<rte>\n");
1427 2 : WriteFeatureAttributes(poFeature);
1428 5 : for(i=0;i<n;i++)
1429 : {
1430 3 : double lat = line->getY(i);
1431 3 : double lon = line->getX(i);
1432 3 : CheckAndFixCoordinatesValidity(&lat, &lon);
1433 3 : poDS->AddCoord(lon, lat);
1434 3 : VSIFPrintf(fp, " <rtept lat=\"%.15f\" lon=\"%.15f\">\n", lat, lon);
1435 6 : if (poGeom->getGeometryType() == wkbLineString25D ||
1436 3 : poGeom->getGeometryType() == wkbMultiLineString25D)
1437 : {
1438 0 : VSIFPrintf(fp, " <ele>%f</ele>\n", line->getZ(i));
1439 : }
1440 3 : VSIFPrintf(fp, " </rtept>\n");
1441 : }
1442 2 : VSIFPrintf(fp, "</rte>\n");
1443 : }
1444 : else
1445 : {
1446 3 : poDS->SetLastGPXGeomTypeWritten(gpxGeomType);
1447 :
1448 3 : if (poGeom == NULL)
1449 : {
1450 0 : VSIFPrintf(fp, "<trk>\n");
1451 0 : WriteFeatureAttributes(poFeature);
1452 0 : VSIFPrintf(fp, "</trk>\n");
1453 0 : return OGRERR_NONE;
1454 : }
1455 :
1456 3 : switch( poGeom->getGeometryType() )
1457 : {
1458 : case wkbLineString:
1459 : case wkbLineString25D:
1460 : {
1461 0 : OGRLineString* line = (OGRLineString*)poGeom;
1462 0 : int n = line->getNumPoints();
1463 : int i;
1464 0 : VSIFPrintf(fp, "<trk>\n");
1465 0 : WriteFeatureAttributes(poFeature);
1466 0 : VSIFPrintf(fp, " <trkseg>\n");
1467 0 : for(i=0;i<n;i++)
1468 : {
1469 0 : double lat = line->getY(i);
1470 0 : double lon = line->getX(i);
1471 0 : CheckAndFixCoordinatesValidity(&lat, &lon);
1472 0 : poDS->AddCoord(lon, lat);
1473 0 : VSIFPrintf(fp, " <trkpt lat=\"%.15f\" lon=\"%.15f\">\n", lat, lon);
1474 0 : if (line->getGeometryType() == wkbLineString25D)
1475 : {
1476 0 : VSIFPrintf(fp, " <ele>%f</ele>\n", line->getZ(i));
1477 : }
1478 0 : VSIFPrintf(fp, " </trkpt>\n");
1479 : }
1480 0 : VSIFPrintf(fp, " </trkseg>\n");
1481 0 : VSIFPrintf(fp, "</trk>\n");
1482 0 : break;
1483 : }
1484 :
1485 : case wkbMultiLineString:
1486 : case wkbMultiLineString25D:
1487 : {
1488 3 : int nGeometries = ((OGRGeometryCollection*)poGeom)->getNumGeometries ();
1489 3 : VSIFPrintf(fp, "<trk>\n");
1490 3 : WriteFeatureAttributes(poFeature);
1491 : int j;
1492 6 : for(j=0;j<nGeometries;j++)
1493 : {
1494 3 : OGRLineString* line = (OGRLineString*) ( ((OGRGeometryCollection*)poGeom)->getGeometryRef(j) );
1495 3 : int n = (line) ? line->getNumPoints() : 0;
1496 : int i;
1497 3 : VSIFPrintf(fp, " <trkseg>\n");
1498 7 : for(i=0;i<n;i++)
1499 : {
1500 4 : double lat = line->getY(i);
1501 4 : double lon = line->getX(i);
1502 4 : CheckAndFixCoordinatesValidity(&lat, &lon);
1503 4 : poDS->AddCoord(lon, lat);
1504 4 : VSIFPrintf(fp, " <trkpt lat=\"%.15f\" lon=\"%.15f\">\n", lat, lon);
1505 4 : if (line->getGeometryType() == wkbLineString25D)
1506 : {
1507 0 : VSIFPrintf(fp, " <ele>%f</ele>\n", line->getZ(i));
1508 : }
1509 4 : VSIFPrintf(fp, " </trkpt>\n");
1510 : }
1511 3 : VSIFPrintf(fp, " </trkseg>\n");
1512 : }
1513 3 : VSIFPrintf(fp, "</trk>\n");
1514 3 : break;
1515 : }
1516 :
1517 : default:
1518 : {
1519 : CPLError( CE_Failure, CPLE_NotSupported,
1520 : "Geometry type of `%s' not supported for 'trk' element.\n",
1521 0 : OGRGeometryTypeToName(poGeom->getGeometryType()) );
1522 0 : return OGRERR_FAILURE;
1523 : }
1524 : }
1525 : }
1526 :
1527 9 : return OGRERR_NONE;
1528 : }
1529 :
1530 :
1531 :
1532 : /************************************************************************/
1533 : /* CreateField() */
1534 : /************************************************************************/
1535 :
1536 :
1537 3 : OGRErr OGRGPXLayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
1538 :
1539 : {
1540 75 : for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
1541 : {
1542 72 : if (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
1543 : poField->GetNameRef() ) == 0)
1544 : {
1545 0 : return OGRERR_NONE;
1546 : }
1547 : }
1548 3 : if (poDS->GetUseExtensions() == FALSE)
1549 : {
1550 : CPLError(CE_Failure, CPLE_NotSupported,
1551 : "Field of name '%s' is not supported in GPX schema. "
1552 : "Use GPX_USE_EXTENSIONS creation option to allow use of the <extensions> element.",
1553 0 : poField->GetNameRef());
1554 0 : return OGRERR_FAILURE;
1555 : }
1556 : else
1557 : {
1558 3 : poFeatureDefn->AddFieldDefn( poField );
1559 3 : return OGRERR_NONE;
1560 : }
1561 : }
1562 :
1563 : /************************************************************************/
1564 : /* TestCapability() */
1565 : /************************************************************************/
1566 :
1567 0 : int OGRGPXLayer::TestCapability( const char * pszCap )
1568 :
1569 : {
1570 0 : if( EQUAL(pszCap,OLCSequentialWrite) )
1571 0 : return bWriteMode;
1572 :
1573 0 : else if( EQUAL(pszCap,OLCStringsAsUTF8) )
1574 0 : return TRUE;
1575 :
1576 : else
1577 0 : return FALSE;
1578 : }
1579 :
1580 :
1581 : /************************************************************************/
1582 : /* LoadExtensionsSchema() */
1583 : /************************************************************************/
1584 :
1585 : #ifdef HAVE_EXPAT
1586 :
1587 310 : static void XMLCALL startElementLoadSchemaCbk(void *pUserData, const char *pszName, const char **ppszAttr)
1588 : {
1589 310 : ((OGRGPXLayer*)pUserData)->startElementLoadSchemaCbk(pszName, ppszAttr);
1590 310 : }
1591 :
1592 310 : static void XMLCALL endElementLoadSchemaCbk(void *pUserData, const char *pszName)
1593 : {
1594 310 : ((OGRGPXLayer*)pUserData)->endElementLoadSchemaCbk(pszName);
1595 310 : }
1596 :
1597 855 : static void XMLCALL dataHandlerLoadSchemaCbk(void *pUserData, const char *data, int nLen)
1598 : {
1599 855 : ((OGRGPXLayer*)pUserData)->dataHandlerLoadSchemaCbk(data, nLen);
1600 855 : }
1601 :
1602 :
1603 : /** This function parses the whole file to detect the extensions fields */
1604 10 : void OGRGPXLayer::LoadExtensionsSchema()
1605 : {
1606 10 : oSchemaParser = OGRCreateExpatXMLParser();
1607 10 : XML_SetElementHandler(oSchemaParser, ::startElementLoadSchemaCbk, ::endElementLoadSchemaCbk);
1608 10 : XML_SetCharacterDataHandler(oSchemaParser, ::dataHandlerLoadSchemaCbk);
1609 10 : XML_SetUserData(oSchemaParser, this);
1610 :
1611 10 : VSIFSeekL( fpGPX, 0, SEEK_SET );
1612 :
1613 10 : inInterestingElement = FALSE;
1614 10 : inExtensions = FALSE;
1615 10 : depthLevel = 0;
1616 10 : currentFieldDefn = NULL;
1617 10 : pszSubElementName = NULL;
1618 10 : pszSubElementValue = NULL;
1619 10 : nSubElementValueLen = 0;
1620 10 : nWithoutEventCounter = 0;
1621 10 : bStopParsing = FALSE;
1622 :
1623 : char aBuf[BUFSIZ];
1624 : int nDone;
1625 10 : do
1626 : {
1627 10 : nDataHandlerCounter = 0;
1628 10 : unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGPX );
1629 10 : nDone = VSIFEofL(fpGPX);
1630 10 : if (XML_Parse(oSchemaParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
1631 : {
1632 : CPLError(CE_Failure, CPLE_AppDefined,
1633 : "XML parsing of GPX file failed : %s at line %d, column %d",
1634 : XML_ErrorString(XML_GetErrorCode(oSchemaParser)),
1635 : (int)XML_GetCurrentLineNumber(oSchemaParser),
1636 0 : (int)XML_GetCurrentColumnNumber(oSchemaParser));
1637 0 : bStopParsing = TRUE;
1638 0 : break;
1639 : }
1640 10 : nWithoutEventCounter ++;
1641 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1642 :
1643 10 : if (nWithoutEventCounter == 10)
1644 : {
1645 : CPLError(CE_Failure, CPLE_AppDefined,
1646 0 : "Too much data inside one element. File probably corrupted");
1647 0 : bStopParsing = TRUE;
1648 : }
1649 :
1650 10 : XML_ParserFree(oSchemaParser);
1651 10 : oSchemaParser = NULL;
1652 :
1653 10 : VSIFSeekL( fpGPX, 0, SEEK_SET );
1654 10 : }
1655 :
1656 :
1657 : /************************************************************************/
1658 : /* startElementLoadSchemaCbk() */
1659 : /************************************************************************/
1660 :
1661 :
1662 310 : void OGRGPXLayer::startElementLoadSchemaCbk(const char *pszName, const char **ppszAttr)
1663 : {
1664 310 : if (bStopParsing) return;
1665 :
1666 310 : nWithoutEventCounter = 0;
1667 :
1668 314 : if (gpxGeomType == GPX_WPT && strcmp(pszName, "wpt") == 0)
1669 : {
1670 4 : inInterestingElement = TRUE;
1671 4 : inExtensions = FALSE;
1672 4 : interestingDepthLevel = depthLevel;
1673 : }
1674 309 : else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trk") == 0)
1675 : {
1676 3 : inInterestingElement = TRUE;
1677 3 : inExtensions = FALSE;
1678 3 : interestingDepthLevel = depthLevel;
1679 : }
1680 305 : else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rte") == 0)
1681 : {
1682 2 : inInterestingElement = TRUE;
1683 2 : inExtensions = FALSE;
1684 2 : interestingDepthLevel = depthLevel;
1685 : }
1686 305 : else if (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkpt") == 0)
1687 : {
1688 4 : inInterestingElement = TRUE;
1689 4 : inExtensions = FALSE;
1690 4 : interestingDepthLevel = depthLevel;
1691 : }
1692 300 : else if (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rtept") == 0)
1693 : {
1694 3 : inInterestingElement = TRUE;
1695 3 : inExtensions = FALSE;
1696 3 : interestingDepthLevel = depthLevel;
1697 : }
1698 294 : else if (inInterestingElement)
1699 : {
1700 62 : if (depthLevel == interestingDepthLevel + 1 &&
1701 : strcmp(pszName, "extensions") == 0)
1702 : {
1703 3 : inExtensions = TRUE;
1704 3 : extensionsDepthLevel = depthLevel;
1705 : }
1706 56 : else if (inExtensions && depthLevel == extensionsDepthLevel + 1)
1707 : {
1708 6 : CPLFree(pszSubElementName);
1709 6 : pszSubElementName = CPLStrdup(pszName);
1710 :
1711 : int iField;
1712 150 : for(iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
1713 : {
1714 : int bMatch;
1715 147 : if (iField >= nGPXFields)
1716 : {
1717 9 : char* pszCompatibleName = OGRGPX_GetOGRCompatibleTagName(pszName);
1718 9 : bMatch = (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), pszCompatibleName ) == 0);
1719 9 : CPLFree(pszCompatibleName);
1720 : }
1721 : else
1722 138 : bMatch = (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), pszName ) == 0);
1723 :
1724 147 : if (bMatch)
1725 : {
1726 3 : currentFieldDefn = poFeatureDefn->GetFieldDefn(iField);
1727 3 : break;
1728 : }
1729 : }
1730 6 : if (iField == poFeatureDefn->GetFieldCount())
1731 : {
1732 3 : char* pszCompatibleName = OGRGPX_GetOGRCompatibleTagName(pszName);
1733 3 : OGRFieldDefn newFieldDefn(pszCompatibleName, OFTInteger);
1734 3 : CPLFree(pszCompatibleName);
1735 :
1736 3 : poFeatureDefn->AddFieldDefn(&newFieldDefn);
1737 3 : currentFieldDefn = poFeatureDefn->GetFieldDefn(poFeatureDefn->GetFieldCount() - 1);
1738 :
1739 3 : if (poFeatureDefn->GetFieldCount() == 100)
1740 : {
1741 : CPLError(CE_Failure, CPLE_AppDefined,
1742 0 : "Too many fields. File probably corrupted");
1743 0 : XML_StopParser(oSchemaParser, XML_FALSE);
1744 0 : bStopParsing = TRUE;
1745 3 : }
1746 : }
1747 : }
1748 : }
1749 :
1750 310 : depthLevel++;
1751 : }
1752 :
1753 :
1754 : /************************************************************************/
1755 : /* endElementLoadSchemaCbk() */
1756 : /************************************************************************/
1757 :
1758 0 : static int OGRGPXIsInt(const char* pszStr)
1759 : {
1760 : int i;
1761 :
1762 0 : while(*pszStr == ' ')
1763 0 : pszStr++;
1764 :
1765 0 : for(i=0;pszStr[i];i++)
1766 : {
1767 0 : if (pszStr[i] == '+' || pszStr[i] == '-')
1768 : {
1769 0 : if (i != 0)
1770 0 : return FALSE;
1771 : }
1772 0 : else if (!(pszStr[i] >= '0' && pszStr[i] <= '9'))
1773 0 : return FALSE;
1774 : }
1775 0 : return TRUE;
1776 : }
1777 :
1778 :
1779 310 : void OGRGPXLayer::endElementLoadSchemaCbk(const char *pszName)
1780 : {
1781 310 : if (bStopParsing) return;
1782 :
1783 310 : nWithoutEventCounter = 0;
1784 :
1785 310 : depthLevel--;
1786 :
1787 310 : if (inInterestingElement)
1788 : {
1789 79 : if (gpxGeomType == GPX_WPT && strcmp(pszName, "wpt") == 0)
1790 : {
1791 4 : inInterestingElement = FALSE;
1792 4 : inExtensions = FALSE;
1793 : }
1794 74 : else if (gpxGeomType == GPX_TRACK && strcmp(pszName, "trk") == 0)
1795 : {
1796 3 : inInterestingElement = FALSE;
1797 3 : inExtensions = FALSE;
1798 : }
1799 70 : else if (gpxGeomType == GPX_ROUTE && strcmp(pszName, "rte") == 0)
1800 : {
1801 2 : inInterestingElement = FALSE;
1802 2 : inExtensions = FALSE;
1803 : }
1804 70 : else if (gpxGeomType == GPX_TRACK_POINT && strcmp(pszName, "trkpt") == 0)
1805 : {
1806 4 : inInterestingElement = FALSE;
1807 4 : inExtensions = FALSE;
1808 : }
1809 65 : else if (gpxGeomType == GPX_ROUTE_POINT && strcmp(pszName, "rtept") == 0)
1810 : {
1811 3 : inInterestingElement = FALSE;
1812 3 : inExtensions = FALSE;
1813 : }
1814 62 : else if (depthLevel == interestingDepthLevel + 1 &&
1815 : strcmp(pszName, "extensions") == 0)
1816 : {
1817 3 : inExtensions = FALSE;
1818 : }
1819 56 : else if (inExtensions && depthLevel == extensionsDepthLevel + 1 &&
1820 : pszSubElementName && strcmp(pszName, pszSubElementName) == 0)
1821 : {
1822 6 : if (pszSubElementValue && nSubElementValueLen && currentFieldDefn)
1823 : {
1824 5 : pszSubElementValue[nSubElementValueLen] = 0;
1825 5 : if (currentFieldDefn->GetType() == OFTInteger ||
1826 : currentFieldDefn->GetType() == OFTReal)
1827 : {
1828 3 : char* pszRemainingStr = NULL;
1829 3 : CPLStrtod(pszSubElementValue, &pszRemainingStr);
1830 3 : if (pszRemainingStr == NULL ||
1831 : *pszRemainingStr == 0 ||
1832 : *pszRemainingStr == ' ')
1833 : {
1834 0 : if (currentFieldDefn->GetType() == OFTInteger)
1835 : {
1836 0 : if (OGRGPXIsInt(pszSubElementValue) == FALSE)
1837 : {
1838 0 : currentFieldDefn->SetType(OFTReal);
1839 : }
1840 : }
1841 : }
1842 : else
1843 : {
1844 3 : currentFieldDefn->SetType(OFTString);
1845 : }
1846 : }
1847 : }
1848 :
1849 6 : CPLFree(pszSubElementName);
1850 6 : pszSubElementName = NULL;
1851 6 : CPLFree(pszSubElementValue);
1852 6 : pszSubElementValue = NULL;
1853 6 : nSubElementValueLen = 0;
1854 6 : currentFieldDefn = NULL;
1855 : }
1856 : }
1857 : }
1858 :
1859 : /************************************************************************/
1860 : /* dataHandlerLoadSchemaCbk() */
1861 : /************************************************************************/
1862 :
1863 855 : void OGRGPXLayer::dataHandlerLoadSchemaCbk(const char *data, int nLen)
1864 : {
1865 855 : if (bStopParsing) return;
1866 :
1867 855 : nDataHandlerCounter ++;
1868 855 : if (nDataHandlerCounter >= BUFSIZ)
1869 : {
1870 0 : CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
1871 0 : XML_StopParser(oSchemaParser, XML_FALSE);
1872 0 : bStopParsing = TRUE;
1873 0 : return;
1874 : }
1875 :
1876 855 : nWithoutEventCounter = 0;
1877 :
1878 855 : if (pszSubElementName)
1879 : {
1880 5 : char* pszNewSubElementValue = (char*) VSIRealloc(pszSubElementValue, nSubElementValueLen + nLen + 1);
1881 5 : if (pszNewSubElementValue == NULL)
1882 : {
1883 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
1884 0 : XML_StopParser(oSchemaParser, XML_FALSE);
1885 0 : bStopParsing = TRUE;
1886 0 : return;
1887 : }
1888 5 : pszSubElementValue = pszNewSubElementValue;
1889 5 : memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
1890 5 : nSubElementValueLen += nLen;
1891 5 : if (nSubElementValueLen > 100000)
1892 : {
1893 : CPLError(CE_Failure, CPLE_AppDefined,
1894 0 : "Too much data inside one element. File probably corrupted");
1895 0 : XML_StopParser(oSchemaParser, XML_FALSE);
1896 0 : bStopParsing = TRUE;
1897 : }
1898 : }
1899 : }
1900 : #else
1901 : void OGRGPXLayer::LoadExtensionsSchema()
1902 : {
1903 : }
1904 : #endif
|