diff options
author | willemferguson <willemferguson@zoology.up.ac.za> | 2020-01-25 10:06:54 +0200 |
---|---|---|
committer | Lubomir I. Ivanov <neolit123@gmail.com> | 2020-01-25 23:25:33 +0200 |
commit | ff18de053f338d0f100e7994db6ef5a2cac6280a (patch) | |
tree | 506b3205823f64f5a3f7e0da5652bcd28f627a0f /core | |
parent | 1e14c3f0d38ac8ef9f0726daf1d8f0c990da6ef2 (diff) | |
download | subsurface-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.cpp | 155 |
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; } |