From bc0e8b94c30f2bf3b8927e9837deba0400da6efc Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Wed, 1 Nov 2023 07:16:44 -0600 Subject: [PATCH] refactor garmin_fs class (#1203) * use container for garmin_fs ilinks. and leave memory management up to the copy on write container. * make gmsd const for read only usage. this prevents the possiblity of detachment of the ilinks list. * incorporate some variables and functions into garmin_fs_t * unify garmin category conversions. * fiddle with test time zone sensitivity. * add utc option for garmin_txt reader. * correct sign of adjustment * update garmin_txt includes. --- garmin.cc | 4 +- garmin_fs.cc | 95 ++++++++++++---------------------- garmin_fs.h | 50 +++++++++--------- garmin_gpi.cc | 6 +-- garmin_txt.cc | 84 +++++++++++++++--------------- gdb.cc | 53 +++++++------------ gdb.h | 2 +- gpx.cc | 39 +++++++------- random.cc | 4 +- reference/garmincategories.gpx | 35 +++++++++++++ reference/garmincategories.txt | 7 +++ testo.d/gpx.test | 7 +++ unicsv.cc | 8 +-- util.cc | 4 +- waypt.cc | 18 +++---- xcsv.cc | 20 +++---- 16 files changed, 219 insertions(+), 217 deletions(-) create mode 100644 reference/garmincategories.gpx create mode 100644 reference/garmincategories.txt diff --git a/garmin.cc b/garmin.cc index 1382f9ead..dd04edc42 100644 --- a/garmin.cc +++ b/garmin.cc @@ -1241,7 +1241,7 @@ d103_icon_number_from_symbol(const QString& s) static void garmin_fs_garmin_after_read(const GPS_PWay way, Waypoint* wpt, const int protoid) { - garmin_fs_t* gmsd = garmin_fs_alloc(protoid); + auto* gmsd = new garmin_fs_t(protoid); wpt->fs.FsChainAdd(gmsd); /* nothing happens until gmsd is allocated some lines above */ @@ -1275,7 +1275,7 @@ garmin_fs_garmin_after_read(const GPS_PWay way, Waypoint* wpt, const int protoid static void garmin_fs_garmin_before_write(const Waypoint* wpt, GPS_PWay way, const int protoid) { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); (void)protoid; // unused for now. diff --git a/garmin_fs.cc b/garmin_fs.cc index 148db9169..525523005 100644 --- a/garmin_fs.cc +++ b/garmin_fs.cc @@ -29,92 +29,61 @@ #include "inifile.h" // for inifile_readstr -#define MYNAME "garmin_fs" - -garmin_fs_t* -garmin_fs_alloc(const int protocol) -{ - auto* result = new garmin_fs_t; - - result->protocol = protocol; - - return result; -} - -garmin_fs_t* garmin_fs_t::clone() const +std::optional +garmin_fs_t::convert_category(const QString& category_name) { - auto* copy = new garmin_fs_t(*this); + std::optional category; - /* do not deep copy interlinks, only increment the reference counter */ - if (ilinks != nullptr) { - ilinks->ref_count++; - } - -#ifdef GMSD_EXPERIMENTAL - memcopy(subclass, other.subclass, sizeof(subclass)); -#endif - - return copy; -} - -garmin_fs_t::~garmin_fs_t() -{ - garmin_ilink_t* links; - if ((links = ilinks) != nullptr) { - links->ref_count--; - if (links->ref_count <= 0) { - while (links != nullptr) { - garmin_ilink_t* tmp = links; - links = links->next; - xfree(tmp); - } - } - } -} - -bool -garmin_fs_convert_category(const QString& category_name, uint16_t* category) -{ // Is the name "Category" followed by a number? Use that number. if (category_name.startsWith(u"Category ", Qt::CaseInsensitive)) { bool ok; int i = category_name.mid(9).toInt(&ok); if (ok && (i >= 1) && (i <= 16)) { - *category = (1 << --i); - return true; + category = (1 << --i); + return category; } } if (global_opts.inifile != nullptr) { // Do we have a gpsbabel.ini that maps category names to category #'s? for (int i = 0; i < 16; i++) { QString key = QString::number(i + 1); - QString c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key); + QString c = inifile_readstr(global_opts.inifile, kGmsdSectionCategories, key); if (c.compare(category_name, Qt::CaseInsensitive) == 0) { - *category = (1 << i); - return true; + category = (1 << i); + return category; } } } - return false; + return category; } -bool -garmin_fs_merge_category(const QString& category_name, Waypoint* waypt) +QStringList +garmin_fs_t::print_categories(uint16_t categories) { - uint16_t cat; + QStringList categoryList; - // Attempt to get a textual category name to a category number. - if (!garmin_fs_convert_category(category_name, &cat)) { - return false; + if (categories == 0) { + return categoryList; } - garmin_fs_t* gmsd = garmin_fs_t::find(waypt); - cat = cat | (garmin_fs_t::get_category(gmsd, 0)); + for (int i = 0; i < 16; i++) { + if ((categories & 1) != 0) { + QString c; + if (global_opts.inifile != nullptr) { + QString key = QString::number(i + 1); + c = inifile_readstr(global_opts.inifile, kGmsdSectionCategories, key); + } - if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); - waypt->fs.FsChainAdd(gmsd); + if (c.isNull()) { + categoryList << QString::asprintf("Category %d", i+1); + } +// *fout << QString::asprintf("%s", gps_categories[i]); + else { + categoryList << c; + } + + } + categories = categories >> 1; } - garmin_fs_t::set_category(gmsd, cat); - return true; + return categoryList; } diff --git a/garmin_fs.h b/garmin_fs.h index 0535d85ac..ac74e8957 100644 --- a/garmin_fs.h +++ b/garmin_fs.h @@ -25,7 +25,9 @@ #define GARMIN_FS_H #include // for int32_t, int16_t, uint16_t +#include // for optional +#include // for QList #include // for QString #include "defs.h" @@ -41,9 +43,9 @@ */ struct garmin_ilink_t { - int ref_count; - double lat, lon, alt; - garmin_ilink_t* next; + double lat; + double lon; + double alt; }; struct garmin_fs_flags_t { @@ -95,6 +97,8 @@ struct garmin_fs_flags_t { class garmin_fs_t : public FormatSpecificData { public: + /* Data Members */ + garmin_fs_flags_t flags; int protocol{0}; /* ... used by device (-1 is MapSource) */ @@ -117,26 +121,30 @@ class garmin_fs_t : public FormatSpecificData { QString email; /* email address */ unsigned int duration; /* expected travel time to next route point, in seconds, only when auto-routed */ - garmin_ilink_t* ilinks{nullptr}; + QList ilinks; #ifdef GMSD_EXPERIMENTAL char subclass[22]{}; #endif -public: + /* Special Member Functions */ + garmin_fs_t() : FormatSpecificData(kFsGmsd) {} -private: - garmin_fs_t(const garmin_fs_t& other) = default; -public: - garmin_fs_t& operator=(const garmin_fs_t& rhs) = delete; /* not implemented */ - garmin_fs_t(garmin_fs_t&&) = delete; /* not implemented */ - garmin_fs_t& operator=(garmin_fs_t&&) = delete; /* not implemented */ - ~garmin_fs_t() override; + explicit garmin_fs_t(int p) : garmin_fs_t() {protocol = p;} + + /* Member Functions */ + + garmin_fs_t* clone() const override + { + return new garmin_fs_t(*this); + } - garmin_fs_t* clone() const override; static garmin_fs_t* find(const Waypoint* wpt) { return reinterpret_cast(wpt->fs.FsChainFind(kFsGmsd)); } + static std::optional convert_category(const QString& category_name); + static QStringList print_categories(uint16_t categories); + #define GEN_GMSD_METHODS(field) \ static bool has_##field(const garmin_fs_t* gmsd) \ { \ @@ -212,18 +220,10 @@ class garmin_fs_t : public FormatSpecificData { GEN_GMSD_STR_METHODS(email) #undef GEN_GMSD_STR_METHODS -}; - -garmin_fs_t* garmin_fs_alloc(int protocol); -void garmin_fs_destroy(void* fs); -void garmin_fs_copy(void** dest, const void* src); - -/* ..convert_category: returns true=OK; false=Unable to convert category */ -bool garmin_fs_convert_category(const QString& category_name, uint16_t* category); -/* ..merge_category: returns true=OK; false=Unable to convert category */ -bool garmin_fs_merge_category(const QString& category_name, Waypoint* waypt); - -#define GMSD_SECTION_CATEGORIES "Garmin Categories" +private: + /* Constants */ + static constexpr char kGmsdSectionCategories[] = "Garmin Categories"; +}; #endif diff --git a/garmin_gpi.cc b/garmin_gpi.cc index 340c823be..3f9a824fb 100644 --- a/garmin_gpi.cc +++ b/garmin_gpi.cc @@ -41,7 +41,7 @@ #include "defs.h" #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t #include "gbfile.h" // for gbfputint32, gbfgetint32, gbfgetint16, gbfputint16, gbfgetc, gbfputc, gbfread, gbftell, gbfwrite, gbfseek, gbfclose, gbfopen_le, gbfgetuint16, gbsize_t, gbfile #include "jeeps/gpsmath.h" // for GPS_Math_Deg_To_Semi, GPS_Math_Semi_To_Deg @@ -76,7 +76,7 @@ GarminGPIFormat::gpi_gmsd_init(Waypoint* wpt) } garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); } return gmsd; @@ -700,7 +700,7 @@ GarminGPIFormat::wdata_compute_size(writer_data_t* data) const res = 23; /* bounds, ... of tag 0x80008 */ foreach (Waypoint* wpt, data->waypt_list) { - garmin_fs_t* gmsd; + const garmin_fs_t* gmsd; res += 12; /* tag/sz/sub-sz */ res += 19; /* poi fixed size */ diff --git a/garmin_txt.cc b/garmin_txt.cc index c49569445..8a6a1433f 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -33,6 +33,7 @@ #include // for abs #include // for strstr, strlen #include // for time_t, gmtime, localtime, strftime +#include // for optional #include // for pair, make_pair #include // for QByteArray @@ -49,9 +50,8 @@ #include "csv_util.h" // for csv_linesplit #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_alloc, garmin_fs_convert_category, GMSD_SECTION_CATEGORIES +#include "garmin_fs.h" // for garmin_fs_t #include "garmin_tables.h" // for gt_display_modes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_get_mps_grid_longname, gt_lookup_datum_index, gt_lookup_grid_type, GDB, gt_get_icao_cc, gt_get_icao_country, gt_get_mps_datum_name, gt_waypt_class_names, GT_DISPLAY_MODE... -#include "inifile.h" // for inifile_readstr #include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS84_To_UKOSMap_M #include "src/core/datetime.h" // for DateTime #include "src/core/logging.h" // for Fatal @@ -221,7 +221,7 @@ convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon) static void enum_waypt_cb(const Waypoint* wpt) { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); int wpt_class = garmin_fs_t::get_wpt_class(gmsd, 0); if (wpt_class < 0x80) { if (gtxt_flags.enum_waypoints) { /* enumerate only */ @@ -393,30 +393,9 @@ print_date_and_time(const time_t time, const bool time_only) static void print_categories(uint16_t categories) { - if (categories == 0) { - return; - } - - int count = 0; - for (int i = 0; i < 16; i++) { - if ((categories & 1) != 0) { - QString c; - if (global_opts.inifile != nullptr) { - QString key = QString::number(i + 1); - c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key); - } - - *fout << QString::asprintf("%s", (count++ > 0) ? "," : ""); - if (c.isNull()) { - *fout << QString::asprintf("Category %d", i+1); - } -// *fout << QString::asprintf("%s", gps_categories[i]); - else { - *fout << c; - } - - } - categories = categories >> 1; + const QStringList categoryList = garmin_fs_t::print_categories(categories); + if (!categoryList.isEmpty()) { + *fout << categoryList.join(','); } } @@ -528,7 +507,7 @@ write_waypt(const Waypoint* wpt) { const char* wpt_type; - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); int i = garmin_fs_t::get_display(gmsd, 0); if (i > GT_DISPLAY_MODE_MAX) { @@ -740,6 +719,28 @@ track_disp_wpt_cb(const Waypoint* wpt) * %%% global callbacks called by gpsbabel main process %%% * *******************************************************************************/ +static void +garmin_txt_utc_option() +{ + if (opt_utc != nullptr) { + if (case_ignore_strcmp(opt_utc, "utc") == 0) { + utc_offs = 0; + } else { + utc_offs = xstrtoi(opt_utc, nullptr, 10); + } + utc_offs *= (60 * 60); + gtxt_flags.utc = 1; + } +} + +static void +garmin_txt_adjust_time(QDateTime& dt) +{ + if (gtxt_flags.utc) { + dt = dt.toUTC().addSecs(dt.offsetFromUtc() - utc_offs); + } +} + static void garmin_txt_wr_init(const QString& fname) { @@ -786,15 +787,7 @@ garmin_txt_wr_init(const QString& fname) datum_index = gt_lookup_datum_index(datum_str, MYNAME); } - if (opt_utc != nullptr) { - if (case_ignore_strcmp(opt_utc, "utc") == 0) { - utc_offs = 0; - } else { - utc_offs = xstrtoi(opt_utc, nullptr, 10); - } - utc_offs *= (60 * 60); - gtxt_flags.utc = 1; - } + garmin_txt_utc_option(); } static void @@ -902,7 +895,7 @@ strftime_to_timespec(const char* s) q += "yyyy"; continue; case 'H': - q += "hh"; + q += "HH"; continue; case 'M': q += "mm"; @@ -931,8 +924,11 @@ strftime_to_timespec(const char* s) case 'F': q += "yyyy-MM-dd"; continue; + case 'p': + q += "AP"; + continue; default: - q += s[i+1]; + warning(MYNAME ": omitting unknown strptime conversion \"%%%c\" in \"%s\"\n", s[i], s); break; } } @@ -964,11 +960,10 @@ parse_categories(const QString& str) for (const auto& catstring : catstrings) { QString cin = catstring.trimmed(); if (!cin.isEmpty()) { - uint16_t val; - if (!garmin_fs_convert_category(cin, &val)) { + if (std::optional cat = garmin_fs_t::convert_category(cin); !cat.has_value()) { warning(MYNAME ": Unable to convert category \"%s\" at line %d!\n", qPrintable(cin), current_line); } else { - res = res | val; + res = res | *cat; } } } @@ -1102,7 +1097,7 @@ parse_waypoint(const QStringList& lineparts) bind_fields(waypt_header); auto* wpt = new Waypoint; - garmin_fs_t* gmsd = garmin_fs_alloc(-1); + auto* gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); for (const auto& str : lineparts) { @@ -1184,6 +1179,7 @@ parse_waypoint(const QStringList& lineparts) break; case 16: if (QDateTime dt = parse_date_and_time(str); dt.isValid()) { + garmin_txt_adjust_time(dt); wpt->SetCreationTime(dt); } break; @@ -1319,6 +1315,7 @@ parse_track_waypoint(const QStringList& lineparts) break; case 2: if (QDateTime dt = parse_date_and_time(str); dt.isValid()) { + garmin_txt_adjust_time(dt); wpt->SetCreationTime(dt); } break; @@ -1367,6 +1364,7 @@ garmin_txt_rd_init(const QString& fname) grid_index = (grid_type) -1; init_date_and_time_format(); + garmin_txt_utc_option(); } static void diff --git a/gdb.cc b/gdb.cc index 5efbb55f3..db3bec6a5 100644 --- a/gdb.cc +++ b/gdb.cc @@ -42,7 +42,7 @@ #include "defs.h" // for Waypoint, warning, route_head, fatal, UrlLink, bounds, UrlList, unknown_alt, xfree, waypt_add_to_bounds, waypt_init_bounds, xstrtoi, route_add_wpt, route_disp_all, waypt_bounds_valid, xmalloc, gb_color, WaypointList, find_wa... #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t #include "garmin_tables.h" // for gt_waypt_class_map_point, gt_color_index_by_rgb, gt_color_value, gt_waypt_classes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_gdb_display_mode_symbol, gt_get_icao_country, gt_waypt_class_user_waypoint, GDB, gt_display_mode_symbol #include "gbfile.h" // for gbfgetint32, gbfputint32, gbfgetc, gbfread, gbfwrite, gbfgetdbl, gbfputc, gbfgetcstr, gbfclose, gbfgetnativecstr, gbfopen_le, gbfputint16, gbfile, gbfcopyfrom, gbfputcstr, gbfrewind, gbfseek, gbftell, gbfgetcstr_old, gbfgetint16, gbfgetuint32, gbfputdbl #include "grtcirc.h" // for RAD, gcdist, radtometers @@ -440,7 +440,7 @@ GdbFormat::read_waypoint(gt_waypt_classes_e* waypt_class_out) waypt_ct++; res = new Waypoint; - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); res->fs.FsChainAdd(gmsd); res->shortname = fread_cstr(); wpt_class = (gt_waypt_classes_e) FREAD_i32; @@ -738,46 +738,37 @@ GdbFormat::read_route() } int links = FREAD_i32; - garmin_ilink_t* il_anchor = nullptr; - garmin_ilink_t* il_root = nullptr; + QList il_list; #if GDB_DEBUG DBG(GDB_DBG_RTE, links) printf(MYNAME "-rte_pt \"%s\" (%d): %d interlink step(s)\n", qPrintable(wpt->shortname), wpt_class, links); #endif for (int j = 0; j < links; j++) { - auto* il_step = (garmin_ilink_t*) xmalloc(sizeof(garmin_ilink_t)); + garmin_ilink_t il_step; - il_step->ref_count = 1; - - il_step->lat = FREAD_LATLON; - il_step->lon = FREAD_LATLON; + il_step.lat = FREAD_LATLON; + il_step.lon = FREAD_LATLON; if (FREAD_C == 1) { - il_step->alt = FREAD_DBL; + il_step.alt = FREAD_DBL; } else { - il_step->alt = unknown_alt; + il_step.alt = unknown_alt; } if (j == 0) { - wpt->latitude = il_step->lat; - wpt->longitude = il_step->lon; - wpt->altitude = il_step->alt; + wpt->latitude = il_step.lat; + wpt->longitude = il_step.lon; + wpt->altitude = il_step.alt; } - il_step->next = nullptr; - if (il_anchor == nullptr) { - il_root = il_step; - } else { - il_anchor->next = il_step; - } - il_anchor = il_step; + il_list.append(il_step); #if GDB_DEBUG DBG(GDB_DBG_RTEe, true) { printf(MYNAME "-rte_il \"%s\" (%d of %d): %c%0.6f %c%0.6f\n", qPrintable(wpt->shortname), j + 1, links, - il_step->lat < 0 ? 'S' : 'N', il_step->lat, - il_step->lon < 0 ? 'W' : 'E', il_step->lon); + il_step.lat < 0 ? 'S' : 'N', il_step.lat, + il_step.lon < 0 ? 'W' : 'E', il_step.lon); } #endif } @@ -832,19 +823,13 @@ GdbFormat::read_route() if (wpt != nullptr) { garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); } garmin_fs_t::set_wpt_class(gmsd, wpt_class); - gmsd->ilinks = il_root; - il_root = nullptr; + gmsd->ilinks = il_list; } - while (il_root) { - garmin_ilink_t* il = il_root; - il_root = il_root->next; - xfree(il); - } } /* ENDFOR: for (i = 0; i < points; i++) */ /* VERSION DEPENDENT CODE */ @@ -1194,7 +1179,7 @@ GdbFormat::gdb_check_waypt(Waypoint* wpt) void GdbFormat::write_waypoint( - const Waypoint* wpt, const QString& shortname, garmin_fs_t* gmsd, + const Waypoint* wpt, const QString& shortname, const garmin_fs_t* gmsd, const int icon, const int display) { char zbuf[32], ffbuf[32]; @@ -1391,7 +1376,7 @@ GdbFormat::write_route(const route_head* rte, const QString& rte_name) fatal(MYNAME ": Sorry, that should never happen!!!\n"); } - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); /* extra_data may contain a modified shortname */ gdb_write_cstr((wpt->extra_data) ? *static_cast(wpt->extra_data) : wpt->shortname); @@ -1564,7 +1549,7 @@ GdbFormat::write_waypoint_cb(const Waypoint* refpt) fout = ftmp; /* prepare the waypoint */ - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); int wpt_class = garmin_fs_t::get_wpt_class(gmsd, -1); if (wpt_class == -1) { diff --git a/gdb.h b/gdb.h index 6697ca592..fc3497401 100644 --- a/gdb.h +++ b/gdb.h @@ -150,7 +150,7 @@ class GdbFormat : public Format void reset_short_handle(const char* defname); void write_header(); static void gdb_check_waypt(Waypoint* wpt); - void write_waypoint(const Waypoint* wpt, const QString& shortname, garmin_fs_t* gmsd, int icon, int display); + void write_waypoint(const Waypoint* wpt, const QString& shortname, const garmin_fs_t* gmsd, int icon, int display); static void route_compute_bounds(const route_head* rte, bounds* bounds); void route_write_bounds(bounds* bounds) const; void write_route(const route_head* rte, const QString& rte_name); diff --git a/gpx.cc b/gpx.cc index de176e454..176ecc676 100644 --- a/gpx.cc +++ b/gpx.cc @@ -47,7 +47,7 @@ #include // for qAsConst, QAddConst<>::Type #include "defs.h" -#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t, garmin_fs_alloc, garmin_fs_merge_category +#include "garmin_fs.h" // for garmin_fs_t, garmin_ilink_t #include "garmin_tables.h" // for gt_color_index_by_rgb, gt_color_name, gt_color_value_by_name #include "geocache.h" // for Geocache, Geocache::UtfSt... #include "mkshort.h" // for MakeShort @@ -218,7 +218,7 @@ GpxFormat::tag_garmin_fs(tag_type tag, const QString& text, Waypoint* waypt) { garmin_fs_t* gmsd = garmin_fs_t::find(waypt); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); waypt->fs.FsChainAdd(gmsd); } @@ -243,7 +243,10 @@ GpxFormat::tag_garmin_fs(tag_type tag, const QString& text, Waypoint* waypt) } break; case tag_type::garmin_wpt_category: - if (!garmin_fs_merge_category(text, waypt)) { + if (auto cat = garmin_fs_t::convert_category(text); cat.has_value()) { + cat = *cat | (garmin_fs_t::get_category(gmsd, 0)); + garmin_fs_t::set_category(gmsd, *cat); + } else { // There's nothing a user can really do about this (well, they could // create a gpsbabel.ini that mapped them to garmin category numbers // but that feature is so obscure and used in so few outputs that @@ -1346,7 +1349,7 @@ GpxFormat::gpx_write_common_extensions(const Waypoint* waypointp, const gpx_poin // Although not required by the schema we assume that gpxx:RoutePointExtension must be a child of gpx:rtept. // Although not required by the schema we assume that gpxx:TrackPointExtension must be a child of gpx:trkpt. // Although not required by the schema we assume that gpxtpx:TrackPointExtension must be a child of gpx:trkpt. - garmin_fs_t* gmsd = garmin_fs_t::find(waypointp); + const garmin_fs_t* gmsd = garmin_fs_t::find(waypointp); switch (point_type) { case gpxpt_waypoint: writer->stackOptionalStartElement(QStringLiteral("gpxx:WaypointExtension")); @@ -1379,11 +1382,9 @@ GpxFormat::gpx_write_common_extensions(const Waypoint* waypointp, const gpx_poin if (garmin_fs_t::has_category(gmsd)) { uint16_t cx = gmsd->category; writer->stackStartElement(QStringLiteral("gpxx:Categories")); - for (int i = 0; i < 16; i++) { - if (cx & 1) { - writer->stackTextElement(QStringLiteral("gpxx:Category"), QStringLiteral("Category %1").arg(i+1)); - } - cx = cx >> 1; + const QStringList categoryList = garmin_fs_t::print_categories(cx); + for (const auto& text : categoryList) { + writer->stackTextElement(QStringLiteral("gpxx:Category"), text); } writer->stackEndElement(); // gpxx:Categories } @@ -1401,19 +1402,21 @@ GpxFormat::gpx_write_common_extensions(const Waypoint* waypointp, const gpx_poin writer->stackEndElement(); // gpxx:WaypointExtension break; case gpxpt_route: - if (gmsd != nullptr && gmsd->ilinks != nullptr) { + if (gmsd != nullptr && !gmsd->ilinks.isEmpty()) { writer->stackOptionalStartElement(QStringLiteral("gpxx:RoutePointExtension")); - garmin_ilink_t* link = gmsd->ilinks; - garmin_ilink_t* prior = nullptr; // GDB files sometime contain repeated point; omit them - while (link != nullptr) { - if (prior == nullptr || prior->lat != link->lat || prior->lon != link->lon) { + double prior_lat; // GDB files sometime contain repeated point; omit them + double prior_lon; + bool first = true; + for (const auto& link : gmsd->ilinks) { + if (first || (prior_lat != link.lat) || (prior_lon != link.lon)) { writer->stackStartElement(QStringLiteral("gpxx:rpt")); - writer->stackAttribute(QStringLiteral("lat"), toString(link->lat)); - writer->stackAttribute(QStringLiteral("lon"), toString(link->lon)); + writer->stackAttribute(QStringLiteral("lat"), toString(link.lat)); + writer->stackAttribute(QStringLiteral("lon"), toString(link.lon)); writer->stackEndElement(); // "gpxx:rpt" + prior_lat = link.lat; + prior_lon = link.lon; + first = false; } - prior = link; - link = link->next; } writer->stackEndElement(); // gpxx:RoutePointExtension } diff --git a/random.cc b/random.cc index 7026a9e53..339c04602 100644 --- a/random.cc +++ b/random.cc @@ -28,7 +28,7 @@ #include "defs.h" #include "random.h" #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, GMSD_SET, garmin_fs_flags_t, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t, GMSD_SET, garmin_fs_flags_t #include "src/core/datetime.h" // for DateTime @@ -104,7 +104,7 @@ Waypoint* RandomFormat::random_generate_wpt(int i, const QDateTime& time, const Waypoint* prev) { auto* wpt = new Waypoint; - garmin_fs_t* gmsd = garmin_fs_alloc(-1); + auto* gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); do { diff --git a/reference/garmincategories.gpx b/reference/garmincategories.gpx new file mode 100644 index 000000000..95b140d19 --- /dev/null +++ b/reference/garmincategories.gpx @@ -0,0 +1,35 @@ + + + + + + + + + Hwy 119 + The Diagonal + The Diagonal + Flag, Blue + + + SymbolAndName + + Slow food + Category 11 + + + + + + + Hwy 72 + The Peak to Peak + The Peak to Peak + Flag, Blue + + + SymbolAndName + + + + diff --git a/reference/garmincategories.txt b/reference/garmincategories.txt new file mode 100644 index 000000000..b7ec5292c --- /dev/null +++ b/reference/garmincategories.txt @@ -0,0 +1,7 @@ +Grid Lat/Lon hddd°mm.mmm' +Datum WGS 84 + +Header Name Description Type Position Altitude Depth Proximity Temperature Display Mode Color Symbol Facility City State Country Date Modified Link Categories + +Waypoint Hwy 119 The Diagonal User Waypoint N39 58.432183 W105 27.951022 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:12 PM Slow food,Category 11 +Waypoint Hwy 72 The Peak to Peak User Waypoint N40 00.238037 W105 29.937744 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:02 PM diff --git a/testo.d/gpx.test b/testo.d/gpx.test index 85581adf4..f917b2a2e 100644 --- a/testo.d/gpx.test +++ b/testo.d/gpx.test @@ -79,6 +79,13 @@ compare ${REFERENCE}/gpxpassthrough10~gpx.gpx ${TMPDIR}/gpxpassthrough10~gpx.gpx gpsbabel -i gpx -f ${REFERENCE}/gpxpassthrough11.gpx -o gpx -F ${TMPDIR}/gpxpassthrough11~gpx.gpx compare ${REFERENCE}/gpxpassthrough11~gpx.gpx ${TMPDIR}/gpxpassthrough11~gpx.gpx +# garmin specific categories +gpsbabel -p gpsbabel-sample.ini -i gpx -f ${REFERENCE}/garmincategories.gpx -o garmin_txt,utc=-7 -F ${TMPDIR}/garmincategories~gpx.txt +compare ${REFERENCE}/garmincategories.txt ${TMPDIR}/garmincategories~gpx.txt + +gpsbabel -p gpsbabel-sample.ini -i garmin_txt,utc=-7 -f ${REFERENCE}/garmincategories.txt -o gpx,garminextensions -F ${TMPDIR}/garmincategories~txt.gpx +compare ${REFERENCE}/garmincategories.gpx ${TMPDIR}/garmincategories~txt.gpx + if [ -z "${VALGRIND}" ]; then set -e if command -v xmllint > /dev/null; diff --git a/unicsv.cc b/unicsv.cc index 92ca85043..679c19ad4 100644 --- a/unicsv.cc +++ b/unicsv.cc @@ -42,7 +42,7 @@ #include "defs.h" #include "csv_util.h" // for csv_linesplit, human_to_dec #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_flags_t, garmin_fs_t, GMSD_GET, GMSD_HAS, GMSD_SETQSTR, GMSD_FIND, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t #include "garmin_tables.h" // for gt_lookup_datum_index, gt_get_mps_grid_longname, gt_lookup_grid_type #include "geocache.h" // for Geocache, Geocache::status_t, Geoc... #include "jeeps/gpsmath.h" // for GPS_Math_UKOSMap_To_WGS84_M, GPS_Math_EN_To_UKOSNG_Map, GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_Known_Datum_To_WGS84_M, GPS_Math_Swiss_EN_To_WGS84, GPS_Math_UTM_EN_To_Known_Datum, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS... @@ -823,7 +823,7 @@ UnicsvFormat::unicsv_parse_one_line(const QString& ibuf) case fld_garmin_facility: gmsd = garmin_fs_t::find(wpt); if (! gmsd) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); } switch (unicsv_fields_tab[column]) { @@ -1113,7 +1113,7 @@ void UnicsvFormat::unicsv_waypt_enum_cb(const Waypoint* wpt) { const QString& shortname = wpt->shortname; - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (!shortname.isEmpty()) { unicsv_outp_flags[fld_shortname] = true; @@ -1264,7 +1264,7 @@ UnicsvFormat::unicsv_waypt_disp_cb(const Waypoint* wpt) unicsv_waypt_ct++; QString shortname = wpt->shortname; - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (unicsv_datum_idx == kDautmWGS84) { lat = wpt->latitude; diff --git a/util.cc b/util.cc index e1723f533..c625e95d4 100644 --- a/util.cc +++ b/util.cc @@ -623,7 +623,7 @@ convert_human_date_format(const char* human_datef) } if (okay == 0) { - fatal("Invalid character \"%c\" in date format!", *cin); + fatal("Invalid character \"%c\" in date format \"%s\"!\n", *cin, human_datef); } } QString rv(result); @@ -717,7 +717,7 @@ convert_human_time_format(const char* human_timef) } if (okay == 0) { - fatal("Invalid character \"%c\" in time format!", *cin); + fatal("Invalid character \"%c\" in time format \"%s\"!\n", *cin, human_timef); } } QString rv(result); diff --git a/waypt.cc b/waypt.cc index 8130add75..77a219faa 100644 --- a/waypt.cc +++ b/waypt.cc @@ -230,22 +230,20 @@ double waypt_distance_ex(const Waypoint* A, const Waypoint* B) { double res = 0; - garmin_fs_t* gmsd; if ((A == nullptr) || (B == nullptr)) { return 0; } - if ((gmsd = garmin_fs_t::find(A)) && (gmsd->ilinks != nullptr)) { - garmin_ilink_t* link = gmsd->ilinks; - - res = gcgeodist(A->latitude, A->longitude, link->lat, link->lon); - while (link->next != nullptr) { - garmin_ilink_t* prev = link; - link = link->next; - res += gcgeodist(prev->lat, prev->lon, link->lat, link->lon); + if (const garmin_fs_t* gmsd = garmin_fs_t::find(A); (gmsd != nullptr) && (!gmsd->ilinks.isEmpty())) { + auto prev_lat = A->latitude; + auto prev_lon = A->longitude; + for (const auto& link : gmsd->ilinks) { + res += gcgeodist(prev_lat, prev_lon, link.lat, link.lon); + prev_lat = link.lat; + prev_lon = link.lon; } - res += gcgeodist(link->lat, link->lon, B->latitude, B->longitude); + res += gcgeodist(gmsd->ilinks.last().lat, gmsd->ilinks.last().lon, B->latitude, B->longitude); } else { res = gcgeodist(A->latitude, A->longitude, B->latitude, B->longitude); } diff --git a/xcsv.cc b/xcsv.cc index d2c57e549..d649fff55 100644 --- a/xcsv.cc +++ b/xcsv.cc @@ -51,7 +51,7 @@ #include "defs.h" #include "csv_util.h" // for csv_stringtrim, dec_to_human, csv_stringclean, human_to_dec, ddmmdir_to_degrees, dec_to_intdeg, decdir_to_dec, intdeg_to_dec, csv_linesplit #include "formspec.h" // for FormatSpecificDataList -#include "garmin_fs.h" // for garmin_fs_t, garmin_fs_alloc +#include "garmin_fs.h" // for garmin_fs_t #include "geocache.h" // for Geocache, Geocache::status_t, Geoc... #include "grtcirc.h" // for RAD, gcdist, radtometers #include "jeeps/gpsmath.h" // for GPS_Math_WGS84_To_UTM_EN, GPS_Lookup_Datum_Index, GPS_Math_Known_Datum_To_WGS84_M, GPS_Math_UTM_EN_To_Known_Datum, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_UKOSMap_M @@ -361,7 +361,7 @@ XcsvFormat::gmsd_init(Waypoint* wpt) { garmin_fs_t* gmsd = garmin_fs_t::find(wpt); if (gmsd == nullptr) { - gmsd = garmin_fs_alloc(-1); + gmsd = new garmin_fs_t(-1); wpt->fs.FsChainAdd(gmsd); } return gmsd; @@ -1534,42 +1534,42 @@ XcsvFormat::xcsv_waypt_pr(const Waypoint* wpt) break; /* GMSD ************************************************************/ case XcsvStyle::XT_COUNTRY: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_country(gmsd, ""))); } break; case XcsvStyle::XT_STATE: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_state(gmsd, ""))); } break; case XcsvStyle::XT_CITY: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_city(gmsd, ""))); } break; case XcsvStyle::XT_POSTAL_CODE: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_postal_code(gmsd, ""))); } break; case XcsvStyle::XT_STREET_ADDR: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_addr(gmsd, ""))); } break; case XcsvStyle::XT_PHONE_NR: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_phone_nr(gmsd, ""))); } break; case XcsvStyle::XT_FACILITY: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_facility(gmsd, ""))); } break; case XcsvStyle::XT_EMAIL: { - garmin_fs_t* gmsd = garmin_fs_t::find(wpt); + const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); buff = QString::asprintf(fmp.printfc.constData(), CSTR(garmin_fs_t::get_email(gmsd, ""))); } break;