1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-02-17 16:20:48 +01:00

Various KML/KMZ parsing fixes and code cleanup

This commit is contained in:
Martin Tůma 2022-09-02 22:53:38 +02:00
parent b156e25023
commit fafe6c4b03
5 changed files with 147 additions and 104 deletions

View File

@ -1,6 +1,7 @@
#include <cctype> #include <cctype>
#include <cmath> #include <cmath>
#include <QFileInfo> #include <QFileInfo>
#include <QTemporaryDir>
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include <QUrl> #include <QUrl>
#include <QCoreApplication> #include <QCoreApplication>
@ -139,3 +140,9 @@ QString Util::displayName(const QString &path)
return path; return path;
#endif // Q_OS_ANDROID #endif // Q_OS_ANDROID
} }
const QTemporaryDir &Util::tempDir()
{
static QTemporaryDir dir;
return dir;
}

View File

@ -3,12 +3,15 @@
#include <QString> #include <QString>
class QTemporaryDir;
namespace Util namespace Util
{ {
int str2int(const char *str, int len); int str2int(const char *str, int len);
double niceNum(double x, bool round); double niceNum(double x, bool round);
QString file2name(const QString &path); QString file2name(const QString &path);
QString displayName(const QString &path); QString displayName(const QString &path);
const QTemporaryDir &tempDir();
} }
#endif // UTIL_H #endif // UTIL_H

View File

@ -11,6 +11,7 @@
#include "common/garmin.h" #include "common/garmin.h"
#include "common/textcodec.h" #include "common/textcodec.h"
#include "common/color.h" #include "common/color.h"
#include "common/util.h"
#include "address.h" #include "address.h"
#include "gpiparser.h" #include "gpiparser.h"
@ -388,12 +389,6 @@ static quint32 readAddress(DataStream &stream, Waypoint &waypoint)
return rs + rh.size; return rs + rh.size;
} }
static const QTemporaryDir &tempDir()
{
static QTemporaryDir dir;
return dir;
}
static quint32 readImageInfo(DataStream &stream, Waypoint &waypoint, static quint32 readImageInfo(DataStream &stream, Waypoint &waypoint,
const QString &fileName, int &imgId) const QString &fileName, int &imgId)
{ {
@ -408,12 +403,12 @@ static quint32 readImageInfo(DataStream &stream, Waypoint &waypoint,
ba.resize(size); ba.resize(size);
stream.readRawData(ba.data(), ba.size()); stream.readRawData(ba.data(), ba.size());
if (tempDir().isValid()) { if (Util::tempDir().isValid()) {
QBuffer buf(&ba); QBuffer buf(&ba);
QImageReader ir(&buf); QImageReader ir(&buf);
QByteArray id(fileName.toUtf8() + QByteArray::number(imgId++)); QByteArray id(fileName.toUtf8() + QByteArray::number(imgId++));
QFile imgFile(tempDir().path() + "/" + QString("%0.%1").arg( QFile imgFile(Util::tempDir().path() + "/" + QString("%0.%1").arg(
QCryptographicHash::hash(id, QCryptographicHash::Sha1).toHex(), QCryptographicHash::hash(id, QCryptographicHash::Sha1).toHex(),
QString(ir.format()))); QString(ir.format())));
imgFile.open(QIODevice::WriteOnly); imgFile.open(QIODevice::WriteOnly);

View File

@ -18,14 +18,9 @@
#include <QUrl> #include <QUrl>
#include <QRegularExpression> #include <QRegularExpression>
#include <private/qzipreader_p.h> #include <private/qzipreader_p.h>
#include "common/util.h"
#include "kmlparser.h" #include "kmlparser.h"
static const QTemporaryDir &tempDir()
{
static QTemporaryDir dir;
return dir;
}
static bool isZIP(QFile *file) static bool isZIP(QFile *file)
{ {
quint32 magic; quint32 magic;
@ -496,6 +491,9 @@ void KMLParser::multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, const QString &name, const QString &desc, QVector<Waypoint> &waypoints, const QString &name, const QString &desc,
const QDateTime &timestamp) const QDateTime &timestamp)
{ {
TrackData *tp = 0;
Area *ap = 0;
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Point")) { if (_reader.name() == QLatin1String("Point")) {
waypoints.append(Waypoint()); waypoints.append(Waypoint());
@ -505,18 +503,22 @@ void KMLParser::multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
w.setTimestamp(timestamp); w.setTimestamp(timestamp);
point(w); point(w);
} else if (_reader.name() == QLatin1String("LineString")) { } else if (_reader.name() == QLatin1String("LineString")) {
tracks.append(TrackData()); if (!tp) {
TrackData &t = tracks.last(); tracks.append(TrackData());
t.append(SegmentData()); tp = &tracks.last();
t.setName(name); tp->setName(name);
t.setDescription(desc); tp->setDescription(desc);
lineString(t.last()); }
tp->append(SegmentData());
lineString(tp->last());
} else if (_reader.name() == QLatin1String("Polygon")) { } else if (_reader.name() == QLatin1String("Polygon")) {
areas.append(Area()); if (!ap) {
Area &a = areas.last(); areas.append(Area());
a.setName(name); ap = &areas.last();
a.setDescription(desc); ap->setName(name);
polygon(a); ap->setDescription(desc);
}
polygon(*ap);
} else } else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
@ -525,65 +527,55 @@ void KMLParser::multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
void KMLParser::photoOverlay(const Ctx &ctx, QVector<Waypoint> &waypoints, void KMLParser::photoOverlay(const Ctx &ctx, QVector<Waypoint> &waypoints,
QMap<QString, QPixmap> &icons) QMap<QString, QPixmap> &icons)
{ {
QString name, desc, phone, address, path, link, id; QString img, id;
QDateTime timestamp; Waypoint w;
static QRegularExpression re("\\$\\[[^\\]]+\\]");
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("name")) if (_reader.name() == QLatin1String("name"))
name = _reader.readElementText(); w.setName(_reader.readElementText());
else if (_reader.name() == QLatin1String("description")) else if (_reader.name() == QLatin1String("description"))
desc = _reader.readElementText(); w.setDescription(_reader.readElementText());
else if (_reader.name() == QLatin1String("phoneNumber")) else if (_reader.name() == QLatin1String("phoneNumber"))
phone = _reader.readElementText(); w.setPhone(_reader.readElementText());
else if (_reader.name() == QLatin1String("address")) else if (_reader.name() == QLatin1String("address"))
address = _reader.readElementText(); w.setAddress(_reader.readElementText());
else if (_reader.name() == QLatin1String("TimeStamp")) else if (_reader.name() == QLatin1String("TimeStamp"))
timestamp = timeStamp(); w.setTimestamp(timeStamp());
else if (_reader.name() == QLatin1String("Style")) else if (_reader.name() == QLatin1String("Style")) {
style(ctx.dir, icons); style(ctx.dir, icons);
else if (_reader.name() == QLatin1String("Icon")) { id = QString();
QString image(icon()); } else if (_reader.name() == QLatin1String("StyleMap"))
styleMap(icons);
QRegularExpression re("\\$\\[[^\\]]+\\]"); else if (_reader.name() == QLatin1String("Icon"))
image.replace(re, "0"); img = icon();
QUrl url(image); else if (_reader.name() == QLatin1String("Point"))
if (url.scheme() == "http" || url.scheme() == "https")
link = image;
else {
if (ctx.zip) {
if (tempDir().isValid()) {
QFileInfo fi(image);
QByteArray id(ctx.path.toUtf8() + image.toUtf8());
path = tempDir().path() + "/" + QString("%0.%1").arg(
QCryptographicHash::hash(id, QCryptographicHash::Sha1)
.toHex(), QString(fi.suffix()));
QFile::rename(ctx.dir.absoluteFilePath(image), path);
}
} else
path = ctx.dir.absoluteFilePath(image);
}
} else if (_reader.name() == QLatin1String("Point")) {
waypoints.append(Waypoint());
Waypoint &w = waypoints.last();
w.setName(name);
w.setDescription(desc);
w.setTimestamp(timestamp);
w.setAddress(address);
w.setPhone(phone);
w.setIcon(icons.value(id));
if (!path.isNull())
w.addImage(path);
if (!link.isNull())
w.addLink(Link(link, "Photo Overlay"));
point(w); point(w);
} else if (_reader.name() == QLatin1String("styleUrl")) { else if (_reader.name() == QLatin1String("styleUrl"))
id = _reader.readElementText(); id = styleUrl();
id = (id.at(0) == '#') ? id.right(id.size() - 1) : QString(); else
} else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
if (!w.coordinates().isNull()) {
w.setIcon(icons.value(id));
img.replace(re, "0");
if (!QUrl(img).scheme().isEmpty())
w.addLink(Link(img, "Photo Overlay"));
else if (ctx.zip && Util::tempDir().isValid()) {
QFileInfo fi(img);
QByteArray id(ctx.path.toUtf8() + img.toUtf8());
QString path(Util::tempDir().path() + "/" + QString("%0.%1")
.arg(QCryptographicHash::hash(id, QCryptographicHash::Sha1)
.toHex(), QString(fi.suffix())));
QFile::rename(ctx.dir.absoluteFilePath(img), path);
w.addImage(path);
} else if (!ctx.zip)
w.addImage(ctx.dir.absoluteFilePath(img));
waypoints.append(w);
}
} }
void KMLParser::placemark(const Ctx &ctx, QList<TrackData> &tracks, void KMLParser::placemark(const Ctx &ctx, QList<TrackData> &tracks,
@ -592,6 +584,9 @@ void KMLParser::placemark(const Ctx &ctx, QList<TrackData> &tracks,
{ {
QString name, desc, phone, address, id; QString name, desc, phone, address, id;
QDateTime timestamp; QDateTime timestamp;
Waypoint *wp = 0;
TrackData *tp = 0;
Area *ap = 0;
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("name")) if (_reader.name() == QLatin1String("name"))
@ -604,53 +599,56 @@ void KMLParser::placemark(const Ctx &ctx, QList<TrackData> &tracks,
address = _reader.readElementText(); address = _reader.readElementText();
else if (_reader.name() == QLatin1String("TimeStamp")) else if (_reader.name() == QLatin1String("TimeStamp"))
timestamp = timeStamp(); timestamp = timeStamp();
else if (_reader.name() == QLatin1String("Style")) else if (_reader.name() == QLatin1String("Style")) {
style(ctx.dir, icons); style(ctx.dir, icons);
id = QString();
} else if (_reader.name() == QLatin1String("StyleMap"))
styleMap(icons);
else if (_reader.name() == QLatin1String("MultiGeometry")) else if (_reader.name() == QLatin1String("MultiGeometry"))
multiGeometry(tracks, areas, waypoints, name, desc, timestamp); multiGeometry(tracks, areas, waypoints, name, desc, timestamp);
else if (_reader.name() == QLatin1String("Point")) { else if (_reader.name() == QLatin1String("Point")) {
waypoints.append(Waypoint()); waypoints.append(Waypoint());
Waypoint &w = waypoints.last(); wp = &waypoints.last();
w.setName(name); point(*wp);
w.setDescription(desc);
w.setTimestamp(timestamp);
w.setAddress(address);
w.setPhone(phone);
w.setIcon(icons.value(id));
point(w);
} else if (_reader.name() == QLatin1String("LineString") } else if (_reader.name() == QLatin1String("LineString")
|| _reader.name() == QLatin1String("LinearRing")) { || _reader.name() == QLatin1String("LinearRing")) {
tracks.append(TrackData()); tracks.append(TrackData());
TrackData &t = tracks.last(); tp = &tracks.last();
t.append(SegmentData()); tp->append(SegmentData());
t.setName(name); lineString(tp->last());
t.setDescription(desc);
lineString(t.last());
} else if (_reader.name() == QLatin1String("Track")) { } else if (_reader.name() == QLatin1String("Track")) {
tracks.append(TrackData()); tracks.append(TrackData());
TrackData &t = tracks.last(); tp = &tracks.last();
t.append(SegmentData()); tp->append(SegmentData());
t.setName(name); track(tp->last());
t.setDescription(desc);
track(t.last());
} else if (_reader.name() == QLatin1String("MultiTrack")) { } else if (_reader.name() == QLatin1String("MultiTrack")) {
tracks.append(TrackData()); tracks.append(TrackData());
TrackData &t = tracks.last(); tp = &tracks.last();
t.setName(name); multiTrack(*tp);
t.setDescription(desc);
multiTrack(t);
} else if (_reader.name() == QLatin1String("Polygon")) { } else if (_reader.name() == QLatin1String("Polygon")) {
areas.append(Area()); areas.append(Area());
Area &a = areas.last(); ap = &areas.last();
a.setName(name); polygon(*ap);
a.setDescription(desc); } else if (_reader.name() == QLatin1String("styleUrl"))
polygon(a); id = styleUrl();
} else if (_reader.name() == QLatin1String("styleUrl")) { else
id = _reader.readElementText();
id = (id.at(0) == '#') ? id.right(id.size() - 1) : QString();
} else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
if (wp) {
wp->setName(name);
wp->setDescription(desc);
wp->setTimestamp(timestamp);
wp->setAddress(address);
wp->setPhone(phone);
wp->setIcon(icons.value(id));
} else if (tp) {
tp->setName(name);
tp->setDescription(desc);
} else if (ap) {
ap->setName(name);
ap->setDescription(desc);
}
} }
QString KMLParser::icon() QString KMLParser::icon()
@ -667,6 +665,12 @@ QString KMLParser::icon()
return path; return path;
} }
QString KMLParser::styleUrl()
{
QString id(_reader.readElementText());
return (id.at(0) == '#') ? id.right(id.size() - 1) : QString();
}
void KMLParser::iconStyle(const QDir &dir, const QString &id, void KMLParser::iconStyle(const QDir &dir, const QString &id,
QMap<QString, QPixmap> &icons) QMap<QString, QPixmap> &icons)
{ {
@ -678,6 +682,35 @@ void KMLParser::iconStyle(const QDir &dir, const QString &id,
} }
} }
void KMLParser::styleMapPair(const QString &id, QMap<QString, QPixmap> &icons)
{
QString key, url;
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("key"))
key = _reader.readElementText();
else if (_reader.name() == QLatin1String("styleUrl"))
url = styleUrl();
else
_reader.skipCurrentElement();
}
if (key == "normal")
icons.insert(id, icons.value(url));
}
void KMLParser::styleMap(QMap<QString, QPixmap> &icons)
{
QString id = _reader.attributes().value("id").toString();
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Pair"))
styleMapPair(id, icons);
else
_reader.skipCurrentElement();
}
}
void KMLParser::style(const QDir &dir, QMap<QString, QPixmap> &icons) void KMLParser::style(const QDir &dir, QMap<QString, QPixmap> &icons)
{ {
QString id = _reader.attributes().value("id").toString(); QString id = _reader.attributes().value("id").toString();
@ -724,6 +757,8 @@ void KMLParser::document(const Ctx &ctx, QList<TrackData> &tracks,
photoOverlay(ctx, waypoints, icons); photoOverlay(ctx, waypoints, icons);
else if (_reader.name() == QLatin1String("Style")) else if (_reader.name() == QLatin1String("Style"))
style(ctx.dir, icons); style(ctx.dir, icons);
else if (_reader.name() == QLatin1String("StyleMap"))
styleMap(icons);
else else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }

View File

@ -58,7 +58,10 @@ private:
qreal number(); qreal number();
QDateTime time(); QDateTime time();
QString icon(); QString icon();
QString styleUrl();
void style(const QDir &dir, QMap<QString, QPixmap> &icons); void style(const QDir &dir, QMap<QString, QPixmap> &icons);
void styleMapPair(const QString &id, QMap<QString, QPixmap> &icons);
void styleMap(QMap<QString, QPixmap> &icons);
void iconStyle(const QDir &dir, const QString &id, void iconStyle(const QDir &dir, const QString &id,
QMap<QString, QPixmap> &icons); QMap<QString, QPixmap> &icons);