From 30a345577a644125502f6e4f8b58ea3077ec8dad Mon Sep 17 00:00:00 2001
From: Robert Lipe <robertlipe@gpsbabel.org>
Date: Mon, 4 Sep 2017 23:20:00 -0500
Subject: [PATCH] Prefer QStringLiteral over implicit conversion from Latin1
 for Q5 5.9. Based on work by Bernd Zeimetz.

---
 gpx.cc      | 14 +++++++-------
 magproto.cc |  6 +++---
 unicsv.cc   |  8 ++++----
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/gpx.cc b/gpx.cc
index 3b3b963c..36701e52 100644
--- gpx.cc
+++ gpx.cc
@@ -494,7 +494,7 @@ tag_cache_desc(const QXmlStreamAttributes& attr)
 {
   cache_descr_is_html = 0;
   if (attr.hasAttribute("html")) {
-    if (attr.value("html").toString().compare("True") == 0) {
+    if (attr.value("html").toString() == QStringLiteral("True")) {
       cache_descr_is_html = 1;
     }
   }
@@ -509,16 +509,16 @@ tag_gs_cache(const QXmlStreamAttributes& attr)
     gc_data->id = attr.value("id").toString().toInt();
   }
   if (attr.hasAttribute("available")) {
-    if (attr.value("available").toString().compare("True", Qt::CaseInsensitive) == 0) {
+    if (attr.value("available").toString().compare(QStringLiteral("True"), Qt::CaseInsensitive) == 0) {
       gc_data->is_available = status_true;
-    } else if (attr.value("available").toString().compare("False", Qt::CaseInsensitive) == 0) {
+    } else if (attr.value("available").toString().compare(QStringLiteral("False"), Qt::CaseInsensitive) == 0) {
       gc_data->is_available = status_false;
     }
   }
   if (attr.hasAttribute("archived")) {
-    if (attr.value("archived").toString().compare("True", Qt::CaseInsensitive) == 0) {
+    if (attr.value("archived").toString().compare(QStringLiteral("True"), Qt::CaseInsensitive) == 0) {
       gc_data->is_archived = status_true;
-    } else if (attr.value("archived").toString().compare("False", Qt::CaseInsensitive) == 0) {
+    } else if (attr.value("archived").toString().compare(QStringLiteral("False"), Qt::CaseInsensitive) == 0) {
       gc_data->is_archived = status_false;
     }
   }
@@ -972,7 +972,7 @@ gpx_end(const QString& el)
      * last date we saw in this log.
      */
   case tt_cache_log_type:
-    if ((cdatastr.compare("Found it") == 0) &&
+    if ((cdatastr.compare(QStringLiteral("Found it")) == 0) &&
         (0 == wpt_tmp->gc_data->last_found.toTime_t())) {
       wpt_tmp->AllocGCData()->last_found = gc_log_date;
     }
@@ -1423,7 +1423,7 @@ fprint_xml_chain(xml_tag* tag, const Waypoint* wpt)
         fprint_xml_chain(tag->child, wpt);
       }
       if (wpt && wpt->gc_data->exported.isValid() &&
-          tag->tagname.compare("groundspeak:cache") == 0) {
+          tag->tagname.compare(QStringLiteral("groundspeak:cache")) == 0) {
         writer->writeTextElement("time",
                                  wpt->gc_data->exported.toPrettyString());
       }
diff --git a/magproto.cc b/magproto.cc
index 7c82e9fb..0deb7f33 100644
--- magproto.cc
+++ magproto.cc
@@ -819,11 +819,11 @@ mag_rd_init_common(const QString& portname)
    */
   QString exten = QFileInfo(curfname).suffix();
   if (exten.length() > 0) {
-    if (0 == exten.compare("upt", Qt::CaseInsensitive)) {
+    if (0 == exten.compare(QStringLiteral("upt"), Qt::CaseInsensitive)) {
       extension_hint = WPTDATAMASK;
-    } else if (0 == exten.compare("log", Qt::CaseInsensitive)) {
+    } else if (0 == exten.compare(QStringLiteral("log"), Qt::CaseInsensitive)) {
       extension_hint = TRKDATAMASK;
-    } else if (0 == exten.compare("rte", Qt::CaseInsensitive)) {
+    } else if (0 == exten.compare(QStringLiteral("rte"), Qt::CaseInsensitive)) {
       extension_hint = RTEDATAMASK;
     }
   }
diff --git a/unicsv.cc b/unicsv.cc
index 4a7d78ed..6312e9d2 100644
--- unicsv.cc
+++ unicsv.cc
@@ -430,13 +430,13 @@ unicsv_parse_time(const QString& str, int* msec, time_t* date)
 static status_type
 unicsv_parse_status(const QString& str)
 {
-  if (str.compare("true", Qt::CaseInsensitive) == 0 ||
-      str.compare("yes", Qt::CaseInsensitive) == 0 ||
+  if (str.compare(QStringLiteral("true"), Qt::CaseInsensitive) == 0 ||
+      str.compare(QStringLiteral("yes"), Qt::CaseInsensitive) == 0 ||
       str == "1") {
     return status_true;
   }
-  if (str.compare("false", Qt::CaseInsensitive) == 0 ||
-      str.compare("no", Qt::CaseInsensitive) == 0 ||
+  if (str.compare(QStringLiteral("false"), Qt::CaseInsensitive) == 0 ||
+      str.compare(QStringLiteral("no"), Qt::CaseInsensitive) == 0 ||
       str == "0") {
     return status_false;
   }
From 604178aa8ad4d3c3ad218df24c1e9a6a1f683bb3 Mon Sep 17 00:00:00 2001
From: Harel Mazor <harel.mazor@gmail.com>
Date: Tue, 24 Jan 2017 00:35:04 +0200
Subject: [PATCH] Added geojson read capablity, moved magic strings to
 constants, fixed windows compilation issues.

---
 GPSBabel.pro  |   4 +-
 geojson.cc    | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 mtk_logger.cc |   5 ++
 tef_xml.cc    |  24 +++----
 4 files changed, 200 insertions(+), 41 deletions(-)

diff --git a/GPSBabel.pro b/GPSBabel.pro
index 4b8e378a..1c06c4ab 100644
--- geojson.cc
+++ geojson.cc
@@ -23,11 +23,30 @@
 #include "src/core/file.h"
 
 static gbfile* ofd;
+static QString input_file_name;
 static const char MYNAME[] = "geojson";
 static char* compact_opt = NULL;
 static QJsonObject* track_object = NULL;
 static QJsonArray* track_coords = NULL;
 
+static const QString FEATURE_COLLECTION = QStringLiteral("FeatureCollection");
+static const QString FEATURE = QStringLiteral("Feature");
+static const QString POINT = QStringLiteral("Point");
+static const QString MULTIPOINT = QStringLiteral("MultiPoint");
+static const QString LINESTRING = QStringLiteral("LineString");
+static const QString MULTILINESTRING = QStringLiteral("MultiLineString");
+static const QString POLYGON = QStringLiteral("Polygon");
+static const QString MULTIPOLYGON = QStringLiteral("MultiPolygon");
+static const QString TYPE = QStringLiteral("type");
+static const QString FEATURES = QStringLiteral("features");
+static const QString COORDINATES = QStringLiteral("coordinates");
+static const QString GEOMETRY = QStringLiteral("geometry");
+static const QString PROPERTIES = QStringLiteral("properties");
+static const QString NAME = QStringLiteral("name");
+static const QString DESCRIPTION = QStringLiteral("description");
+static const QString URL = QStringLiteral("url");
+static const QString URLNAME = QStringLiteral("urlname");
+
 static arglist_t geojson_args[] = {
   {"compact", &compact_opt, "Compact Output. Default is off.", 
     NULL, ARGTYPE_BOOL, ARG_NOMINMAX } ,
@@ -36,6 +55,7 @@ static arglist_t geojson_args[] = {
 
 static void
 geojson_rd_init(const QString& fname) {
+	input_file_name = fname;
 }
 
 QJsonArray* feature_collection = nullptr;
@@ -48,57 +68,55 @@ geojson_wr_init(const QString& fname) {
 
 static void
 geojson_waypt_pr(const Waypoint* waypoint) {
-  QJsonObject object;
-  static const QString kType = QStringLiteral("type");
-  object[kType] = QStringLiteral("Feature");
-  
   QJsonObject geometry;
-  geometry[kType] = QStringLiteral("Point");
-
-  QJsonArray coords;
-  coords.append(waypoint->longitude);
-  coords.append(waypoint->latitude);
+  geometry[TYPE] = POINT;
+  QJsonArray coordinates;
+  coordinates.append(waypoint->longitude);
+  coordinates.append(waypoint->latitude);
   if (waypoint->altitude != unknown_alt && waypoint->altitude != 0) {
-    coords.append(waypoint->altitude);
+    coordinates.append(waypoint->altitude);
   }
+  geometry[COORDINATES] = coordinates;
 
-  geometry[kType] = QStringLiteral("Point");
-  geometry[QStringLiteral("coordinates")] = coords;
-  object[QStringLiteral("geometry")] = geometry;
+  QJsonObject feature;
+  feature[TYPE] = FEATURE;
+  feature[GEOMETRY] = geometry;
 
   // Build up the properties.
   QJsonObject properties;
   if (!waypoint->shortname.isEmpty()) {
-    properties["name"] = waypoint->shortname;
+    properties[NAME] = waypoint->shortname;
   }
   if (!waypoint->description.isEmpty()) {
-    properties["description"] = waypoint->description;
+    properties[DESCRIPTION] = waypoint->description;
   }
   if (waypoint->HasUrlLink()) {
     UrlLink link = waypoint->GetUrlLink();
     if (!link.url_.isEmpty()) {
-      properties["url"] = link.url_;
+      properties[URL] = link.url_;
     }
     if (!link.url_link_text_.isEmpty()) {
-      properties["urlname"] = link.url_link_text_;
+      properties[URLNAME] = link.url_link_text_;
     }
   }
   if (!properties.empty()) {
-    object["properties"] = properties;
+    feature[PROPERTIES] = properties;
   }
   
-  feature_collection->append(object);
+  feature_collection->append(feature);
 }
 
 static void
 geojson_rd_deinit() {
+	gbfclose(ofd);
+	ofd = NULL;
 }
 
 static void
 geojson_wr_deinit(void) {
   QJsonObject object;
-  object[QStringLiteral("type")] = QStringLiteral("FeatureCollection");
-  object[QStringLiteral("features")]  = *feature_collection;
+  object[TYPE] = FEATURE_COLLECTION;
+  object[FEATURES]  = *feature_collection;
 
   QJsonDocument save(object);
   QJsonDocument::JsonFormat style;
@@ -111,21 +129,157 @@ geojson_wr_deinit(void) {
   feature_collection = nullptr;
 }
 
+static Waypoint* 
+waypoint_from_coordinates(const QJsonArray& coordinates)
+{
+	auto waypoint = new Waypoint();
+	waypoint->latitude = coordinates.at(1).toDouble();
+	waypoint->longitude = coordinates.at(0).toDouble();
+	if (coordinates.size() > 2)
+	{
+		waypoint->altitude = coordinates.at(3).toDouble();
+	}
+	return waypoint;
+}
+
+static void 
+routes_from_polygon_coordinates(const QJsonArray& polygon)
+{
+	for (auto lineStringIterator = polygon.begin(); lineStringIterator != polygon.end(); ++lineStringIterator)
+	{
+		QJsonArray coordinates = (*lineStringIterator).toArray();
+		auto route = route_head_alloc();
+		route_add_head(route);
+		for (auto coordinates_iterator = coordinates.begin(); coordinates_iterator != coordinates.end(); ++coordinates_iterator)
+		{
+			auto waypoint = waypoint_from_coordinates((*coordinates_iterator).toArray());
+			route_add_wpt(route, waypoint);
+		}
+	}
+}
+
 static void
 geojson_read(void) {
+	QFile file;
+	file.setFileName(input_file_name);
+	file.open(QIODevice::ReadOnly | QIODevice::Text);
+	QString file_content = file.readAll();
+	file.close();
+	QJsonParseError error;
+	QJsonDocument document = QJsonDocument::fromJson(file_content.toUtf8(), &error);
+	QJsonObject rootObject = document.object();
+
+	if (rootObject[TYPE] != FEATURE_COLLECTION)
+	{
+		return;
+	}
+	QJsonArray features = rootObject.value(FEATURES).toArray();
+	for (auto iterator = features.begin(); iterator != features.end(); ++iterator)
+	{
+		QJsonObject feature = (*iterator).toObject();
+		QJsonObject properties = (feature.value(PROPERTIES)).toObject();
+		QString name;
+		QString description;
+		if (!properties.empty())
+		{
+			if (properties.contains(NAME))
+			{
+				name = properties[NAME].toString();
+			}
+			if (properties.contains(DESCRIPTION))
+			{
+				description = properties[DESCRIPTION].toString();
+			}
+		}
+		
+		QJsonObject geometry = feature.value(GEOMETRY).toObject();
+		auto geometry_type = geometry[TYPE];
+		if (geometry_type == POINT)
+		{
+			QJsonArray coordinates = geometry.value(COORDINATES).toArray();
+			auto waypoint = waypoint_from_coordinates(coordinates);
+			waypoint->shortname = name;
+			waypoint->description = description;
+			if (properties.contains(URL))
+			{
+				QString url = properties[URL].toString();
+				if (properties.contains(URLNAME))
+				{
+					QString url_text = properties[URLNAME].toString();
+					waypoint->AddUrlLink(UrlLink(url, url_text));
+				}
+				else
+				{
+					waypoint->AddUrlLink(UrlLink(url));
+				}
+			}
+			waypt_add(waypoint);
+		}
+		else if (geometry_type == MULTIPOINT)
+		{
+			QJsonArray coordinates = geometry.value(COORDINATES).toArray();
+			for (auto coordinates_iterator = coordinates.begin(); coordinates_iterator != coordinates.end(); ++coordinates_iterator)
+			{
+				auto waypoint = waypoint_from_coordinates((*coordinates_iterator).toArray());
+				waypt_add(waypoint);
+			}
+		}
+		else if (geometry_type == LINESTRING)
+		{
+			QJsonArray coordinates = geometry.value(COORDINATES).toArray();
+			auto route = route_head_alloc();
+			route->rte_name = name;
+			route_add_head(route);
+			for (auto coordinates_iterator = coordinates.begin(); coordinates_iterator != coordinates.end(); ++coordinates_iterator)
+			{
+				auto waypoint = waypoint_from_coordinates((*coordinates_iterator).toArray());
+				route_add_wpt(route, waypoint);
+			}
+		}
+		else if (geometry_type == POLYGON)
+		{
+			QJsonArray polygon = geometry.value(COORDINATES).toArray();
+			routes_from_polygon_coordinates(polygon);
+		}
+		else if (geometry_type == MULTIPOLYGON)
+		{
+			QJsonArray polygons = geometry.value(COORDINATES).toArray();
+			for (auto polygons_iterator = polygons.begin(); polygons_iterator != polygons.end(); ++polygons_iterator)
+			{
+				QJsonArray polygon = (*polygons_iterator).toArray();
+				routes_from_polygon_coordinates(polygon);
+			}
+		}
+		else if (geometry_type == MULTILINESTRING)
+		{
+			QJsonArray line_strings = geometry.value(COORDINATES).toArray();
+			for (auto lineStringIterator = line_strings.begin(); lineStringIterator != line_strings.end(); ++lineStringIterator)
+			{
+				QJsonArray coordinates = (*lineStringIterator).toArray();
+				auto route = route_head_alloc();
+				track_add_head(route);
+				for (auto coordinates_iterator = coordinates.begin(); coordinates_iterator != coordinates.end(); ++coordinates_iterator)
+				{
+					auto waypoint = waypoint_from_coordinates((*coordinates_iterator).toArray());
+					route_add_wpt(route, waypoint);
+				}
+			}
+		}
+	}
 }
 
+
 static void geojson_track_hdr(const route_head* track) {
   track_object = new QJsonObject();
 
-  (*track_object)[QStringLiteral("type")] = QStringLiteral("Feature");
+  (*track_object)[TYPE] = FEATURE;
   track_coords = new QJsonArray();
 
   QJsonObject properties;
   if (!track->rte_name.isEmpty()) {
-    properties["name"] = track->rte_name;
+    properties[NAME] = track->rte_name;
   }
-  (*track_object)["properties"] = properties;
+  (*track_object)[PROPERTIES] = properties;
 }
 
 static void geojson_track_disp(const Waypoint* trackpoint) {
@@ -141,9 +295,9 @@ static void geojson_track_disp(const Waypoint* trackpoint) {
 
 static void geojson_track_tlr(const route_head* track) {
   QJsonObject geometry;
-  geometry[QStringLiteral("type")] = QStringLiteral("LineString");
-  geometry[QStringLiteral("coordinates")] = *track_coords;
-  (*track_object)[QStringLiteral("geometry")] = geometry;
+  geometry[TYPE] = LINESTRING;
+  geometry[COORDINATES] = *track_coords;
+  (*track_object)[GEOMETRY] = geometry;
   feature_collection->append(*track_object);
   delete track_object;
   track_object = NULL;
diff --git a/mtk_logger.cc b/mtk_logger.cc
index 29a2680c..d68fe6db 100644
--- mtk_logger.cc
+++ mtk_logger.cc
@@ -69,6 +69,11 @@
 
 #define MYNAME "mtk_logger"
 
+#ifdef __WIN32__
+#include <io.h>
+#define ftruncate _chsize
+#endif
+
 /* MTK packet id's -- currently unused... */
 enum MTK_NMEA_PACKET {
   PMTK_TEST = 0,
diff --git a/tef_xml.cc b/tef_xml.cc
index b32d69b3..37dd85ba 100644
--- tef_xml.cc
+++ tef_xml.cc
@@ -72,11 +72,11 @@ tef_start(xg_string args, const QXmlStreamAttributes* attrv)
   bool valid = false;
 
   foreach(QXmlStreamAttribute attr, *attrv) {
-    if (attr.name().compare("Comment", Qt::CaseInsensitive) == 0) {
-      if (attr.value().compare("TourExchangeFormat", Qt::CaseInsensitive) == 0) {
+    if (attr.name().compare(QString("Comment"), Qt::CaseInsensitive) == 0) {
+      if (attr.value().compare(QString("TourExchangeFormat"), Qt::CaseInsensitive) == 0) {
         valid = true;
       }
-    } else if (attr.name().compare("Version", Qt::CaseInsensitive) == 0) {
+    } else if (attr.name().compare(QString("Version"), Qt::CaseInsensitive) == 0) {
       version = attr.value().toString().toDouble();
     }
   }
@@ -95,9 +95,9 @@ tef_header(xg_string args, const QXmlStreamAttributes* attrv)
 {
   route = route_head_alloc();
   foreach(QXmlStreamAttribute attr, *attrv) {
-    if (attr.name().compare("Name", Qt::CaseInsensitive) == 0) {
+    if (attr.name().compare(QString("Name"), Qt::CaseInsensitive) == 0) {
       route->rte_name = attr.value().toString().trimmed();
-    } else if (attr.name().compare("Software", Qt::CaseInsensitive) == 0) {
+    } else if (attr.name().compare(QString("Software"), Qt::CaseInsensitive) == 0) {
       route->rte_desc = attr.value().toString().trimmed();
     }
   }
@@ -248,20 +248,20 @@ tef_item_start(xg_string args, const QXmlStreamAttributes* attrv)
     QString attrstr = attr.value().toString();
     QByteArray attrtext = attrstr.toUtf8();
 
-    if (attr.name().compare("SegDescription", Qt::CaseInsensitive) == 0) {
+    if (attr.name().compare(QString("SegDescription"), Qt::CaseInsensitive) == 0) {
       wpt_tmp->shortname = attrstr.trimmed();
-    } else if (attr.name().compare("PointDescription", Qt::CaseInsensitive) == 0) {
+    } else if (attr.name().compare(QString("PointDescription"), Qt::CaseInsensitive) == 0) {
       wpt_tmp->description = attrstr.trimmed();
-    } else if (attr.name().compare("ViaStation", Qt::CaseInsensitive) == 0 &&
-               attr.value().compare("true", Qt::CaseInsensitive) == 0) {
+    } else if (attr.name().compare(QString("ViaStation"), Qt::CaseInsensitive) == 0 &&
+               attr.value().compare(QString("true"), Qt::CaseInsensitive) == 0) {
       wpt_tmp->wpt_flags.fmt_use = 1;  /* only a flag */
 
       /* new in TEF V2 */
-    } else if (attr.name().compare("Instruction", Qt::CaseInsensitive) == 0) {
+    } else if (attr.name().compare(QString("Instruction"), Qt::CaseInsensitive) == 0) {
       wpt_tmp->description = attrstr.trimmed();
-    } else if (attr.name().compare("Altitude", Qt::CaseInsensitive) == 0) {
+    } else if (attr.name().compare(QString("Altitude"), Qt::CaseInsensitive) == 0) {
       wpt_tmp->altitude = attrstr.toDouble();
-    } else if (attr.name().compare("TimeStamp", Qt::CaseInsensitive) == 0) {
+    } else if (attr.name().compare(QString("TimeStamp"), Qt::CaseInsensitive) == 0) {
       /* nothing for the moment */
     }
   }