summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorGravatar willemferguson <willemferguson@zoology.up.ac.za>2020-01-25 10:06:54 +0200
committerGravatar Lubomir I. Ivanov <neolit123@gmail.com>2020-01-25 23:25:33 +0200
commitff18de053f338d0f100e7994db6ef5a2cac6280a (patch)
tree506b3205823f64f5a3f7e0da5652bcd28f627a0f /core
parent1e14c3f0d38ac8ef9f0726daf1d8f0c990da6ef2 (diff)
downloadsubsurface-ff18de053f338d0f100e7994db6ef5a2cac6280a.tar.gz
Parse GPX dive coordinates: Qt XML framework
This replaces the C-code XML parsing with a Qt infrastructure. QXmlStreamReader is used to parse the GPX file. It also takes into account comments by @neolit123 Signed-off-by: willemferguson <willemferguson@zoology.up.ac.za>
Diffstat (limited to 'core')
-rw-r--r--core/parse-gpx.cpp155
1 files changed, 48 insertions, 107 deletions
diff --git a/core/parse-gpx.cpp b/core/parse-gpx.cpp
index 16d2a17a2..d00e59d4d 100644
--- a/core/parse-gpx.cpp
+++ b/core/parse-gpx.cpp
@@ -1,55 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "core/parse-gpx.h"
#include "core/dive.h"
-
-// TODO: instead of manually parsing the XML, we should consider using
-// one of the two XML frameworks that we already use elsewhere in
-// the code
-
-// Read text from the present position in the file until
-// the first 'delim' character is encountered.
-static int getSubstring(QFile *file, QString *bufptr, char delim)
-{
- char c;
- bufptr->clear();
- do {
- if (file->read(&c, 1) <= 0) // EOF
- return 1;
- if (c == delim) break;
- bufptr->append(QChar(c));
- } while (c != delim);
- return 0;
-}
-
-// Find the next occurence of a specified target GPX element in the file,
-// characerised by a "<xxx " or "<xxx>" character sequence.
-// 'target' specifies the name of the element searched for.
-// termc is the ending character of the element name search = '>' or ' '.
-static int findXmlElement(QFile *fileptr, QString target, QString *bufptr, char termc)
-{
- bool match = false;
- char c;
- char skipdelim = (termc == ' ') ? '>' : ' ';
- do { // Skip input until first start new of element (<) is encountered:
- if (getSubstring(fileptr, bufptr, '<'))
- return 1; // EOF
- bufptr->clear();
- do { // Read name of following element and store it in buf
- if (fileptr->read(&c, 1) <= 0) // EOF encountered
- return 1;
- if ((c == '>') || (c == ' ')) // found a valid delimiter
- break;
- bufptr->append(QChar(c));
- } while ((c != '>') && (c != ' '));
- if (*bufptr == "/trk") // End of GPS track found: return EOF
- return 1;
- if (c == skipdelim)
- continue; // if inappropriate delimiter was found, redo from start
- if (*bufptr == target) // Compare xml element name from gpx file with the
- match = true; // the target element searched for.
- } while (match == false);
- return 0;
-}
+#include <QXmlStreamReader>
// Find the coordinates at the time specified in coords.start_dive
// by searching the gpx file "fileName". Here is a typical trkpt element in GPX:
@@ -57,15 +9,15 @@ static int findXmlElement(QFile *fileptr, QString target, QString *bufptr, char
int getCoordsFromGPXFile(struct dive_coords *coords, QString fileName)
{
struct tm tm1;
- time_t when = 0;
- double lon, lat;
- int line = 0;
- int64_t time_offset = coords->settingsDiff_offset + coords->timeZone_offset;
+ time_t trkpt_time = 0;
time_t divetime;
+ int64_t time_offset = coords->settingsDiff_offset + coords->timeZone_offset;
+ double lon = 0, lat = 0;
+ int line = 0;
bool first_line = true;
bool found = false;
+ bool trkpt_found = false;
divetime = coords->start_dive;
- QString buf;
QFile gpxFile;
gpxFile.setFileName(fileName);
if (!gpxFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
@@ -86,61 +38,50 @@ int getCoordsFromGPXFile(struct dive_coords *coords, QString fileName)
dmin = time.tm_min;
#endif
- do {
- line++; // this is the sequence number of the trkpt xml element processed
- // Find next trkpt xml element (This function also detects </trk> that signals EOF):
- if (findXmlElement(&gpxFile, QString("trkpt"), &buf, ' ')) // This is the normal exit point
- break; // for this routine
- // == Get coordinates: ==
- if (getSubstring(&gpxFile, &buf, '"')) // read up to the end of the "lat=" label
- break; // on EOF
- if (buf != "lat=") {
- fprintf(stderr, "GPX parse error: cannot find latitude (trkpt #%d)\n", line);
- return 1;
- }
- if (getSubstring(&gpxFile, &buf, '"')) // read up to the end of the latitude value
- break; // on EOF
- lat = buf.toDouble(); // Convert lat to decimal
- if (getSubstring(&gpxFile, &buf, ' ')) // Read past space char
- break; // on EOF
- if (getSubstring(&gpxFile, &buf, '"')) // Read up to end of "lon=" label
- break; // on EOF
- if (buf != "lon=") {
- fprintf(stderr, "GPX parse error: cannot find longitude (trkpt #%d)\n", line);
- return 1;
- }
- if (getSubstring(&gpxFile, &buf, '"')) // get string with longitude
- break; // on EOF
- lon = buf.toDouble(); // Convert longitude to decimal
- // == get time: ==
- if (findXmlElement(&gpxFile, QString("time"), &buf, '>')) // Find the <time> element
- break; // on EOF
- if (getSubstring(&gpxFile, &buf, '<')) // Read the string containing date/time
- break; // on EOF
- bool ok;
- tm1.tm_year = buf.left(4).toInt(&ok, 10); // Extract the different substrings:
- tm1.tm_mon = buf.mid(5,2).toInt(&ok,10) - 1;
- tm1.tm_mday = buf.mid(8,2).toInt(&ok,10);
- tm1.tm_hour = buf.mid(11,2).toInt(&ok,10);
- tm1.tm_min = buf.mid(14,2).toInt(&ok,10);
- tm1.tm_sec = buf.mid(17,2).toInt(&ok,10);
- when = utc_mktime(&tm1) + time_offset;
- if (first_line) {
- first_line = false;
- coords->start_track = when; // Local time of start of GPS track
- }
- if ((when > divetime && found == false)) { // This GPS local time corresponds to the start time of the dive
- coords->lon = lon; // save the coordinates
- coords->lat = lat;
- found = true;
- }
+ QXmlStreamReader gpxReader(&gpxFile);
+ while (!gpxReader.atEnd()) {
+ gpxReader.readNext();
+ if (gpxReader.isStartElement()) {
+ if (gpxReader.name() == "trkpt") {
+ trkpt_found = true;
+ line++;
+ foreach (const QXmlStreamAttribute &attr, gpxReader.attributes()) {
+ if (attr.name().toString() == QLatin1String("lat"))
+ lat = attr.value().toString().toDouble();
+ else if (attr.name().toString() == QLatin1String("lon"))
+ lon = attr.value().toString().toDouble();
+ }
+ }
+ if (gpxReader.name() == "time" && trkpt_found) { // Ignore the <time> element in the GPX file header
+ QString dateTimeString = gpxReader.readElementText();
+ bool ok;
+ tm1.tm_year = dateTimeString.left(4).toInt(&ok, 10); // Extract the date/time components:
+ tm1.tm_mon = dateTimeString.mid(5,2).toInt(&ok,10) - 1;
+ tm1.tm_mday = dateTimeString.mid(8,2).toInt(&ok,10);
+ tm1.tm_hour = dateTimeString.mid(11,2).toInt(&ok,10);
+ tm1.tm_min = dateTimeString.mid(14,2).toInt(&ok,10);
+ tm1.tm_sec = dateTimeString.mid(17,2).toInt(&ok,10);
+ trkpt_time = utc_mktime(&tm1) + time_offset;
+ if (first_line) {
+ first_line = false;
+ coords->start_track = trkpt_time; // Local time of start of GPS track
+ }
+ if (trkpt_time >= divetime && found == false) { // This GPS local time corresponds to the start time of the dive
+ coords->lon = lon; // save the coordinates
+ coords->lat = lat;
+ found = true;
+ }
+
#ifdef GPSDEBUG
- utc_mkdate(when, &time); // print time and coordinates of each of the trkpt elements of the GPX file
- fprintf(stderr, " %02d: lat=%f lon=%f timestamp=%ld (%ld) %02d/%02d/%02d %02d:%02d dt=%ld %02d/%02d/%02d %02d:%02d\n", line, lat,
- lon, when, time_offset, time.tm_year, time.tm_mon+1, time.tm_mday, time.tm_hour, time.tm_min, divetime, dyr, dmon+1, dday,dhr, dmin );
+ utc_mkdate(trkpt_time, &time); // print coordinates and time of each trkpt element of the GPX file as well as dive start time
+ fprintf(stderr, " %02d: lat=%f lon=%f timestamp=%ld (%ld) %02d/%02d/%02d %02d:%02d dt=%ld %02d/%02d/%02d %02d:%02d\n", line, lat,
+ lon, trkpt_time, time_offset, time.tm_year, time.tm_mon+1, time.tm_mday, time.tm_hour, time.tm_min, divetime, dyr, dmon+1, dday,dhr, dmin);
#endif
- } while (true); // This loop executes until EOF causes a break out of the loop
- coords->end_track = when; // This is the local time of the end of the GPS track
+
+ }
+ }
+ } // while !at.End() // This loop executes until EOF causes a break out of the loop
+ coords->end_track = trkpt_time; // This is the local time of the end of the GPS track
gpxFile.close();
return 0;
}