Skip to content

Commit d0705d1

Browse files
Merge branch 'master' of https://github.com/gpsbabel/gpsbabel into main
2 parents 15bf846 + 7a144a6 commit d0705d1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1536
-932
lines changed

.github/workflows/codeql-analysis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ jobs:
2626
analyze:
2727
name: Analyze
2828
runs-on: ubuntu-latest
29-
container: tsteven4/gpsbabel_build_environment_focal
29+
container:
30+
image: gpsbabel-docker.jfrog.io/tsteven4/gpsbabel_build_environment_focal
31+
env:
32+
CMAKE_GENERATOR: Ninja
3033

3134
strategy:
3235
fail-fast: false

.github/workflows/fedora.yml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,20 @@ jobs:
1414
fail-fast: false
1515
matrix:
1616
# version 32, though obsolete, uses Qt 5.14 so we keep it for that.
17-
version: ['32', '35', '37']
17+
include:
18+
- IMAGE: '32'
19+
CMAKE_PREFIX_PATH: '/usr/lib64/cmake/Qt5'
20+
- IMAGE: '35'
21+
CMAKE_PREFIX_PATH: '/usr/lib64/cmake/Qt5'
22+
- IMAGE: '37'
23+
CMAKE_PREFIX_PATH: '/usr/lib64/cmake/Qt5'
24+
- IMAGE: '37'
25+
CMAKE_PREFIX_PATH: '/usr/lib64/cmake/Qt6'
1826
container:
19-
image: gpsbabel-docker.jfrog.io/tsteven4/gpsbabel_build_environment_f${{ matrix.version }}
27+
image: gpsbabel-docker.jfrog.io/tsteven4/gpsbabel_build_environment_f${{ matrix.IMAGE }}
2028
env:
21-
LC_ALL: C.UTF-8
29+
LC_ALL: 'C.UTF-8'
30+
JOB_CMAKE_PREFIX_PATH: ${{ matrix.CMAKE_PREFIX_PATH }}
2231

2332
steps:
2433
- name: Checkout repository
@@ -28,4 +37,8 @@ jobs:
2837
run: |
2938
# when using containers manually whitelist the checkout directory to allow git commands to work
3039
git config --global --add safe.directory "${GITHUB_WORKSPACE}"
40+
if [ -n "${JOB_CMAKE_PREFIX_PATH}" ]; then
41+
CMAKE_PREFIX_PATH="${JOB_CMAKE_PREFIX_PATH}"
42+
export CMAKE_PREFIX_PATH
43+
fi
3144
./tools/build_and_test_cmake.sh

CMakeLists.txt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ set(ALL_FMTS ${MINIMAL_FMTS}
9090
geocache.cc
9191
geojson.cc
9292
globalsat_sport.cc
93-
gpssim.cc
9493
gtm.cc
9594
gtrnctr.cc
9695
holux.cc
@@ -396,7 +395,6 @@ set(TESTS
396395
geo
397396
globalsat_sport
398397
gpsdrive
399-
gpssim
400398
gpx
401399
grapheme
402400
gtm
@@ -495,17 +493,20 @@ if((CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) AND NOT _isMultiConfig)
495493
add_custom_target(gpsbabel.org
496494
${CMAKE_SOURCE_DIR}/tools/make_gpsbabel_org.sh ${WEB} ${DOCVERSION}
497495
DEPENDS gpsbabel gpsbabel.pdf
498-
VERBATIM)
496+
VERBATIM
497+
USES_TERMINAL)
499498

500499
add_custom_target(gpsbabel.html
501500
${CMAKE_SOURCE_DIR}/tools/make_gpsbabel_html.sh
502501
DEPENDS gpsbabel
503-
VERBATIM)
502+
VERBATIM
503+
USES_TERMINAL)
504504

505505
add_custom_target(gpsbabel.pdf
506506
${CMAKE_SOURCE_DIR}/tools/make_gpsbabel_pdf.sh
507507
DEPENDS gpsbabel
508-
VERBATIM)
508+
VERBATIM
509+
USES_TERMINAL)
509510
else()
510511
message(WARNING "Document generation is only supported for in-source builds with single configuration generators.")
511512
endif()

defs.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ class UrlLink
213213
UrlLink(QString url) :
214214
url_(std::move(url))
215215
{ }
216-
UrlLink(const char* url) :
216+
explicit UrlLink(const char* url) :
217217
url_(url)
218218
{ }
219219
UrlLink(QString url, QString url_link_text) :
@@ -1018,8 +1018,6 @@ inline int case_ignore_strncmp(const QString& s1, const QString& s2, int n)
10181018

10191019
int str_match(const char* str, const char* match);
10201020

1021-
void rtrim(char* s);
1022-
char* lrtrim(char* buff);
10231021
int xasprintf(char** strp, const char* fmt, ...) PRINTFLIKE(2, 3);
10241022
int xasprintf(QString* strp, const char* fmt, ...) PRINTFLIKE(2, 3);
10251023
int xasprintf(QScopedPointer<char, QScopedPointerPodDeleter>& strp, const char* fmt, ...) PRINTFLIKE(2, 3);
File renamed without changes.

exif.cc

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ ExifFormat::exif_find_tag(ExifApp* app, const uint16_t ifd_nr, const uint16_t ta
677677
}
678678

679679
QDateTime
680-
ExifFormat::exif_get_exif_time(ExifApp* app)
680+
ExifFormat::exif_get_exif_time(ExifApp* app) const
681681
{
682682
QDateTime res;
683683

@@ -700,20 +700,24 @@ ExifFormat::exif_get_exif_time(ExifApp* app)
700700
// Exif 2.31 added offset tags to record the offset to UTC.
701701
// If these are present use them, otherwise assume local time.
702702
ExifTag* offset_tag = nullptr;
703+
ExifTag* subsec_tag = nullptr;
703704
switch (tag->id) {
704705
case 0x9003:
705706
offset_tag = exif_find_tag(app, EXIF_IFD, 0x9011); /* OffsetTimeOriginal from EXIF */
707+
subsec_tag = exif_find_tag(app, EXIF_IFD, 0x9291); /* SubSecTimeOriginal from EXIF */
706708
break;
707709
case 0x0132:
708710
offset_tag = exif_find_tag(app, EXIF_IFD, 0x9010); /* OffsetTime from EXIF */
711+
subsec_tag = exif_find_tag(app, EXIF_IFD, 0x9290); /* SubSecTime from EXIF */
709712
break;
710713
case 0x9004:
711714
offset_tag = exif_find_tag(app, EXIF_IFD, 0x9012); /* OffsetTimeDigitized from EXIF */
715+
subsec_tag = exif_find_tag(app, EXIF_IFD, 0x9292); /* SubSecTimeDigitized from EXIF */
712716
break;
713717
}
714718

715-
if (offset_tag) {
716-
QByteArray time_tag = exif_read_str(offset_tag);
719+
if (offset_tag || opt_offsettime) {
720+
QByteArray time_tag = opt_offsettime? QByteArray(opt_offsettime) : exif_read_str(offset_tag);
717721
// string should be +HH:MM or -HH:MM
718722
static const QRegularExpression re(R"(^([+-])(\d{2}):(\d{2})$)");
719723
assert(re.isValid());
@@ -723,10 +727,24 @@ ExifFormat::exif_get_exif_time(ExifApp* app)
723727
int offset_hours = match.captured(1).append(match.captured(2)).toInt();
724728
int offset_mins = match.captured(1).append(match.captured(3)).toInt();
725729
res.setOffsetFromUtc(((offset_hours * 60) + offset_mins) * 60);
730+
} else if (opt_offsettime) {
731+
// Only warn for user supplied offsets.
732+
// Offset tags may indicate the offset was unknown, e.g. " : ".
733+
warning(MYNAME ": OffsetTime is expected to be +HH:MM or -HH:MM, but was %s.\n", time_tag.constData());
726734
}
727735
}
736+
737+
if (subsec_tag) {
738+
QByteArray subsec = exif_read_str(subsec_tag);
739+
bool ok;
740+
double ss = subsec.prepend("0.").toDouble(&ok);
741+
if (ok) {
742+
res = res.addMSecs(lround(1000.0 * ss));
743+
}
744+
}
745+
728746
}
729-
return res;
747+
return res.toUTC();
730748
}
731749

732750
Waypoint*
@@ -895,7 +913,7 @@ ExifFormat::exif_waypt_from_exif_app(ExifApp* app) const
895913
gps_datetime = QDateTime(datestamp, timestamp, Qt::UTC);
896914
if (gps_datetime.isValid()) {
897915
if (global_opts.debug_level >= 3) {
898-
printf(MYNAME "-GPSTimeStamp = %s\n", qPrintable(gps_datetime.toString(Qt::ISODate)));
916+
printf(MYNAME "-GPSTimeStamp = %s\n", qPrintable(gps_datetime.toString(Qt::ISODateWithMs)));
899917
}
900918
wpt->SetCreationTime(gps_datetime);
901919
} else {
@@ -1555,7 +1573,9 @@ ExifFormat::write()
15551573

15561574
exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 0, dt.time().hour());
15571575
exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 1, dt.time().minute());
1558-
exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 2, dt.time().second());
1576+
exif_put_double(GPS_IFD, GPS_IFD_TAG_TIMESTAMP, 2,
1577+
static_cast<double>(dt.time().second()) +
1578+
static_cast<double>(dt.time().msec())/1000.0);
15591579

15601580
exif_put_str(GPS_IFD, GPS_IFD_TAG_DATESTAMP, CSTR(dt.toString(u"yyyy:MM:dd")));
15611581
} else {

exif.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class ExifFormat : public Format
172172
static void exif_examine_app(ExifApp* app);
173173
static ExifIfd* exif_find_ifd(ExifApp* app, uint16_t ifd_nr);
174174
static ExifTag* exif_find_tag(ExifApp* app, uint16_t ifd_nr, uint16_t tag_id);
175-
static QDateTime exif_get_exif_time(ExifApp* app);
175+
QDateTime exif_get_exif_time(ExifApp* app) const;
176176
Waypoint* exif_waypt_from_exif_app(ExifApp* app) const;
177177
static Rational<int> exif_dec2frac(double val, double tolerance);
178178
ExifTag* exif_put_value(int ifd_nr, uint16_t tag_id, uint16_t type, int count, int index, const void* data) const;
@@ -205,12 +205,14 @@ class ExifFormat : public Format
205205
char* opt_overwrite{};
206206
char* opt_frame{};
207207
char* opt_name{};
208+
char* opt_offsettime{};
208209

209210
QVector<arglist_t> exif_args = {
210211
{ "filename", &opt_filename, "Set waypoint name to source filename", "Y", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
211212
{ "frame", &opt_frame, "Time-frame (in seconds)", "10", ARGTYPE_INT, "0", nullptr, nullptr },
212213
{ "name", &opt_name, "Locate waypoint for tagging by this name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
213214
{ "overwrite", &opt_overwrite, "!OVERWRITE! the original file. Default=N", "N", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
215+
{ "offset", &opt_offsettime, "Image Offset Time (+HH:MM or -HH:MM)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
214216
};
215217
};
216218
#endif // EXIF_H_INCLUDED_

format.h

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class Format
4545
{
4646
public:
4747
Format() = default;
48+
Format(const QString& filename) : fname{filename} {}
4849
// Provide virtual public destructor to avoid undefined behavior when
4950
// an object of derived class type is deleted through a pointer to
5051
// its base class type.
@@ -169,28 +170,7 @@ class Format
169170
virtual ff_type get_type() const = 0;
170171
virtual QVector<ff_cap> get_cap() const = 0;
171172

172-
QString get_name() const
173-
{
174-
return name;
175-
}
176-
177-
void set_name(const QString& nm)
178-
{
179-
name = nm;
180-
}
181-
182-
QString get_argstring() const
183-
{
184-
return argstring;
185-
}
186-
187-
void set_argstring(const QString& string)
188-
{
189-
argstring = string;
190-
}
191-
private:
192-
QString name;
193-
QString argstring;
173+
QString fname;
194174

195175
protected:
196176
template <class MyFormat>

garmin.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static int categorybits;
8181
static int receiver_must_upper = 1;
8282
static QTextCodec* codec{nullptr};
8383

84-
static Format* gpx_vec;
84+
static Vecs::fmtinfo_t gpx_vec;
8585

8686
#define MILITANT_VALID_WAYPT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
8787

@@ -355,10 +355,12 @@ rd_init(const QString& fname)
355355
{
356356
if (setjmp(gdx_jmp_buf)) {
357357
const gdx_info* gi = gdx_get_info();
358+
// FIXME: dynamic not implemented.
358359
gpx_vec = Vecs::Instance().find_vec("gpx");
360+
Vecs::prepare_format(gpx_vec);
359361
gpx_vec->rd_init(gi->from_device.canon);
360362
} else {
361-
gpx_vec = nullptr;
363+
gpx_vec = Vecs::fmtinfo_t();
362364
rw_init(fname);
363365
}
364366
}

garmin_txt.cc

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ inline gt_display_modes_e operator++(gt_display_modes_e& s, int) // postfix
116116

117117
#define MAX_HEADER_FIELDS 36
118118

119-
static char* header_lines[unknown_header + 1][MAX_HEADER_FIELDS];
119+
static QString header_lines[unknown_header + 1][MAX_HEADER_FIELDS];
120120
static int header_fields[unknown_header + 1][MAX_HEADER_FIELDS];
121121
static int header_ct[unknown_header + 1];
122122

@@ -869,11 +869,7 @@ static void
869869
free_header(const header_type ht)
870870
{
871871
for (int i = 0; i < MAX_HEADER_FIELDS; i++) {
872-
char* c = header_lines[ht][i];
873-
if (c != nullptr) {
874-
xfree(c);
875-
header_lines[ht][i] = nullptr;
876-
}
872+
header_lines[ht][i].clear();
877873
}
878874
header_ct[ht] = 0;
879875
memset(header_fields[ht], 0, sizeof(header_fields[ht]));
@@ -995,7 +991,8 @@ parse_header(const QStringList& lineparts)
995991

996992
for (const auto& str : lineparts) {
997993
column++;
998-
header_lines[unknown_header][column] = strupper(xstrdup(str));
994+
header_lines[unknown_header][column] = str;
995+
header_lines[unknown_header][column] = header_lines[unknown_header][column].toUpper();
999996
header_ct[unknown_header]++;
1000997
if (header_ct[unknown_header] >= MAX_HEADER_FIELDS) {
1001998
break;
@@ -1044,13 +1041,13 @@ bind_fields(const header_type ht)
10441041
}
10451042

10461043
for (i = 0; i < header_ct[unknown_header]; i++) {
1047-
char* name = header_lines[ht][i] = header_lines[unknown_header][i];
1048-
header_lines[unknown_header][i] = nullptr;
1044+
auto name = header_lines[ht][i] = header_lines[unknown_header][i];
1045+
header_lines[unknown_header][i].clear();
10491046

10501047
c = fields;
10511048
int field_no = 1;
10521049
while (*c) {
1053-
if (strcmp(c, name) == 0) {
1050+
if (name.compare(c) == 0) {
10541051
header_fields[ht][i] = field_no;
10551052
#if 0
10561053
printf("Binding field \"%s\" to internal number %d (%d,%d)\n", name, field_no, ht, i);

geo.cc

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -84,19 +84,9 @@ void GeoFormat::GeoReadLoc(QXmlStreamReader& reader) const
8484
}
8585
}
8686

87-
void GeoFormat::rd_init(const QString& fname)
88-
{
89-
geo_fname = fname;
90-
}
91-
92-
void GeoFormat::rd_deinit()
93-
{
94-
geo_fname.clear();
95-
}
96-
9787
void GeoFormat::read()
9888
{
99-
gpsbabel::File ifile = gpsbabel::File(geo_fname);
89+
gpsbabel::File ifile = gpsbabel::File(fname);
10090
ifile.open(QIODevice::ReadOnly);
10191
QXmlStreamReader reader = QXmlStreamReader(&ifile);
10292

@@ -143,16 +133,6 @@ Geocache::container_t GeoFormat::wpt_container(const QString& args)
143133
return v;
144134
}
145135

146-
void GeoFormat::wr_init(const QString& fname)
147-
{
148-
geo_fname = fname;
149-
}
150-
151-
void GeoFormat::wr_deinit()
152-
{
153-
geo_fname.clear();
154-
}
155-
156136
void GeoFormat::geo_waypt_pr(const Waypoint* waypointp, QXmlStreamWriter& writer)
157137
{
158138
writer.writeStartElement(QStringLiteral("waypoint"));
@@ -221,7 +201,7 @@ void GeoFormat::geo_waypt_pr(const Waypoint* waypointp, QXmlStreamWriter& writer
221201

222202
void GeoFormat::write()
223203
{
224-
gpsbabel::File ofile = gpsbabel::File(geo_fname);
204+
gpsbabel::File ofile = gpsbabel::File(fname);
225205
ofile.open(QIODevice::WriteOnly | QIODevice::Text);
226206
QXmlStreamWriter writer = QXmlStreamWriter(&ofile);
227207

geo.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
class GeoFormat : public Format
3333
{
3434
public:
35+
using Format::Format;
36+
3537
QVector<arglist_t>* get_args() override
3638
{
3739
return &geo_args;
@@ -47,12 +49,12 @@ class GeoFormat : public Format
4749
return { (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none, ff_cap_none };
4850
}
4951

50-
void rd_init(const QString& fname) override;
52+
void rd_init(const QString& fname) override
53+
{}
5154
void read() override;
52-
void rd_deinit() override;
53-
void wr_init(const QString& fname) override;
55+
void wr_init(const QString& fname) override
56+
{}
5457
void write() override;
55-
void wr_deinit() override;
5658

5759
private:
5860

@@ -66,7 +68,6 @@ class GeoFormat : public Format
6668

6769
char* deficon = nullptr;
6870
char* nuke_placer{};
69-
QString geo_fname;
7071

7172
QVector<arglist_t> geo_args = {
7273
{"deficon", &deficon, "Default icon name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },

0 commit comments

Comments
 (0)