summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/CMakeLists.txt1
-rw-r--r--core/parse-gpx.cpp146
-rw-r--r--core/parse-gpx.h22
-rw-r--r--desktop-widgets/importgps.cpp151
-rw-r--r--desktop-widgets/importgps.h15
-rw-r--r--desktop-widgets/locationinformation.cpp2
6 files changed, 177 insertions, 160 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 381276e30..80fbd326e 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -119,6 +119,7 @@ set(SUBSURFACE_CORE_LIB_SRCS
metrics.cpp
metrics.h
ostctools.c
+ parse-gpx.cpp
parse-xml.c
parse.c
parse.h
diff --git a/core/parse-gpx.cpp b/core/parse-gpx.cpp
new file mode 100644
index 000000000..16d2a17a2
--- /dev/null
+++ b/core/parse-gpx.cpp
@@ -0,0 +1,146 @@
+// 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;
+}
+
+// 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:
+// <trkpt lat="-26.84" lon="32.88"><ele>-53.7</ele><time>2017-08-06T04:56:42Z</time></trkpt>
+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 divetime;
+ bool first_line = true;
+ bool found = false;
+ divetime = coords->start_dive;
+ QString buf;
+ QFile gpxFile;
+ gpxFile.setFileName(fileName);
+ if (!gpxFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QByteArray local8bitBAString1 = fileName.toLocal8Bit();
+ char *fname = local8bitBAString1.data(); // convert QString to a C string fileName
+ fprintf(stderr, "GPS file open error: file name = %s\n", fname);
+ return 1;
+ }
+
+#ifdef GPSDEBUG
+ struct tm time; // decode the time of start of dive:
+ utc_mkdate(divetime, &time);
+ int dyr,dmon,dday,dhr,dmin;
+ dyr = time.tm_year;
+ dmon = time.tm_mon;
+ dday = time.tm_mday;
+ dhr = time.tm_hour;
+ 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;
+ }
+#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 );
+#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
+ gpxFile.close();
+ return 0;
+}
diff --git a/core/parse-gpx.h b/core/parse-gpx.h
new file mode 100644
index 000000000..67a29b36f
--- /dev/null
+++ b/core/parse-gpx.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef PARSE_GPX_H
+#define PARSE_GPX_H
+
+
+#include <QFile>
+
+struct dive_coords { // This structure holds important information after parsing the GPX file:
+ time_t start_dive; // Start time of the current dive, obtained using current_dive (local time)
+ time_t end_dive; // End time of current dive (local time)
+ time_t start_track; // Start time of GPX track (UCT)
+ time_t end_track; // End time of GPX track (UCT)
+ double lon; // Longitude of the first trackpoint after the start of the dive
+ double lat; // Latitude of the first trackpoint after the start of the dive
+ int64_t settingsDiff_offset; // Local time difference between dive computer and GPS equipment
+ int64_t timeZone_offset; // UCT international time zone offset of dive site
+};
+
+int getCoordsFromGPXFile(dive_coords *coords, QString fileName);
+
+#endif
+
diff --git a/desktop-widgets/importgps.cpp b/desktop-widgets/importgps.cpp
index 5e4845951..6e36c548a 100644
--- a/desktop-widgets/importgps.cpp
+++ b/desktop-widgets/importgps.cpp
@@ -39,145 +39,6 @@ void ImportGPS::buttonClicked(QAbstractButton *button)
}
}
-// Read text from the present position in the file until
-// the first 'delim' character is encountered.
-int ImportGPS::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 ' '.
-int ImportGPS::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;
-}
-
-// 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:
-// <trkpt lat="-26.84" lon="32.88"><ele>-53.7</ele><time>2017-08-06T04:56:42Z</time></trkpt>
-int ImportGPS::getCoordsFromFile()
-{
- 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 divetime;
- bool first_line = true;
- bool found = false;
- divetime = coords.start_dive;
- QString buf;
- QFile f1;
- f1.setFileName(fileName);
- if (!f1.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QByteArray local8bitBAString1 = fileName.toLocal8Bit();
- char *fname = local8bitBAString1.data(); // convert QString to a C string fileName
- fprintf(stderr, "GPS file open error: file name = %s\n", fname);
- return 1;
- }
-
-#ifdef GPSDEBUG
- struct tm time; // decode the time of start of dive:
- utc_mkdate(divetime, &time);
- int dyr,dmon,dday,dhr,dmin;
- dyr = time.tm_year;
- dmon = time.tm_mon;
- dday = time.tm_mday;
- dhr = time.tm_hour;
- 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(&f1, QString("trkpt"), &buf, ' ')) // This is the normal exit point
- break; // for this routine
- // == Get coordinates: ==
- if (getSubstring(&f1, &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(&f1, &buf, '"')) // read up to the end of the latitude value
- break; // on EOF
- lat = buf.toDouble(); // Convert lat to decimal
- if (getSubstring(&f1, &buf, ' ')) // Read past space char
- break; // on EOF
- if (getSubstring(&f1, &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(&f1, &buf, '"')) // get string with longitude
- break; // on EOF
- lon = buf.toDouble(); // Convert longitude to decimal
- // == get time: ==
- if (findXmlElement(&f1, QString("time"), &buf, '>')) // Find the <time> element
- break; // on EOF
- if (getSubstring(&f1, &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;
- }
-#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 );
-#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
- f1.close();
- return 0;
-}
-
// Fill the visual elements of the synchronisation panel with information
void ImportGPS::updateUI()
{
@@ -247,7 +108,7 @@ void ImportGPS::updateUI()
void ImportGPS::changeZoneForward()
{
coords.timeZone_offset = abs(coords.timeZone_offset);
- getCoordsFromFile(); // If any of the time controls are changed
+ getCoordsFromGPXFile(&coords, fileName); // If any of the time controls are changed
updateUI(); // .. then recalculate the synchronisation
}
@@ -255,14 +116,14 @@ void ImportGPS::changeZoneBackwards()
{
if (coords.timeZone_offset > 0)
coords.timeZone_offset = 0 - coords.timeZone_offset;
- getCoordsFromFile();
+ getCoordsFromGPXFile(&coords, fileName);
updateUI();
}
void ImportGPS::changeDiffForward()
{
coords.settingsDiff_offset = abs(coords.settingsDiff_offset);
- getCoordsFromFile();
+ getCoordsFromGPXFile(&coords, fileName);
updateUI();
}
@@ -270,7 +131,7 @@ void ImportGPS::changeDiffBackwards()
{
if (coords.settingsDiff_offset > 0)
coords.settingsDiff_offset = 0 - coords.settingsDiff_offset;
- getCoordsFromFile();
+ getCoordsFromGPXFile(&coords, fileName);
updateUI();
}
@@ -279,7 +140,7 @@ void ImportGPS::timeDiffEditChanged()
coords.settingsDiff_offset = ui.timeDiffEdit->time().hour() * 3600 + ui.timeDiffEdit->time().minute() * 60;
if (ui.diff_backwards->isChecked())
coords.settingsDiff_offset = 0 - coords.settingsDiff_offset;
- getCoordsFromFile();
+ getCoordsFromGPXFile(&coords, fileName);
updateUI();
}
@@ -288,7 +149,7 @@ void ImportGPS::timeZoneEditChanged()
coords.timeZone_offset = ui.timeZoneEdit->time().hour() * 3600;
if (ui.timezone_backwards->isChecked())
coords.timeZone_offset = 0 - coords.timeZone_offset;
- getCoordsFromFile();
+ getCoordsFromGPXFile(&coords, fileName);
updateUI();
}
diff --git a/desktop-widgets/importgps.h b/desktop-widgets/importgps.h
index 1cef9e57a..9de8c2895 100644
--- a/desktop-widgets/importgps.h
+++ b/desktop-widgets/importgps.h
@@ -4,27 +4,16 @@
#include "ui_importgps.h"
#include "desktop-widgets/locationinformation.h"
+#include "core/parse-gpx.h"
#include <QFile>
-struct dive_coords { // This structure holds important information after parsing the GPX file:
- time_t start_dive; // Start time of the current dive, obtained using current_dive (local time)
- time_t end_dive; // End time of current dive (local time)
- time_t start_track; // Start time of GPX track (UCT)
- time_t end_track; // End time of GPX track (UCT)
- double lon; // Longitude of the first trackpoint after the start of the dive
- double lat; // Latitude of the first trackpoint after the start of the dive
- int64_t settingsDiff_offset; // Local time difference between dive computer and GPS equipment
- int64_t timeZone_offset; // UCT international time zone offset of dive site
-};
-
class ImportGPS : public QDialog {
Q_OBJECT
public:
Ui::ImportGPS ui;
explicit ImportGPS(QWidget *parent, QString fileName, class Ui::LocationInformation *LocationUI);
struct dive_coords coords;
- int getCoordsFromFile();
void updateUI();
private
@@ -40,8 +29,6 @@ slots:
private:
QString fileName;
class Ui::LocationInformation *LocationUI;
- int getSubstring(QFile *f, QString *buf, char delim);
- int findXmlElement(QFile *f, QString target, QString *buf, char termc);
int pixmapSize;
};
diff --git a/desktop-widgets/locationinformation.cpp b/desktop-widgets/locationinformation.cpp
index 1ee848e83..e97a189bd 100644
--- a/desktop-widgets/locationinformation.cpp
+++ b/desktop-widgets/locationinformation.cpp
@@ -235,7 +235,7 @@ void LocationInformationWidget::on_GPSbutton_clicked()
ImportGPS GPSDialog(this, fileName, &ui); // Create a GPS import QDialog
GPSDialog.coords.start_dive = current_dive->when; // initialise
GPSDialog.coords.end_dive = dive_endtime(current_dive);
- if (!GPSDialog.getCoordsFromFile()) { // Get coordinates from GPS file
+ if (getCoordsFromGPXFile(&GPSDialog.coords, fileName) == 0) { // Get coordinates from GPS file
GPSDialog.updateUI(); // If successful, put results in Dialog
if (!GPSDialog.exec()) // and show QDialog
return;