2 WARNING: This code uses internal Qt API - the QZipReader class for reading
3 ZIP files - and things may break if Qt changes the API. For Qt5 this is not
4 a problem as we can "see the future" now and there are no changes in all
5 the supported Qt5 versions up to the last one (5.15). In Qt6 the class
6 might change or even disappear in the future, but this is very unlikely
7 as there were no changes for several years and The Qt Company's policy
8 is: "do not invest any resources into any desktop related stuff unless
9 absolutely necessary". There is an issue (QTBUG-3897) since the year 2009 to
10 include the ZIP reader into the public API, which aptly illustrates the
11 effort The Qt Company is willing to make about anything desktop related...
15 #include <QTemporaryDir>
16 #include <QCryptographicHash>
19 #include <QRegularExpression>
20 #include <private/qzipreader_p.h>
21 #include "common/util.h"
22 #include "kmlparser.h"
24 static bool isZIP(QFile
*file
)
28 return (file
->read((char *)&magic
, sizeof(magic
)) == (qint64
)sizeof(magic
)
29 && qFromLittleEndian(magic
) == 0x04034b50);
32 qreal
KMLParser::number()
35 QString
str(_reader
.readElementText());
40 qreal ret
= str
.toDouble(&res
);
42 _reader
.raiseError(QString("Invalid %1").arg(
43 _reader
.name().toString()));
48 QDateTime
KMLParser::time()
50 QDateTime d
= QDateTime::fromString(_reader
.readElementText(),
53 _reader
.raiseError(QString("Invalid %1").arg(
54 _reader
.name().toString()));
59 bool KMLParser::coord(Trackpoint
&trackpoint
)
61 QString data
= _reader
.readElementText();
62 const QChar
*sp
, *ep
, *cp
, *vp
;
70 sp
= data
.constData();
71 ep
= sp
+ data
.size();
73 for (cp
= sp
; cp
< ep
; cp
++)
77 for (vp
= cp
; cp
<= ep
; cp
++) {
78 if (cp
->isSpace() || cp
->isNull()) {
82 val
[c
] = QString(vp
, cp
- vp
).toDouble(&res
);
87 trackpoint
.setCoordinates(Coordinates(val
[0], val
[1]));
88 if (!trackpoint
.coordinates().isValid())
91 trackpoint
.setElevation(val
[2]);
103 bool KMLParser::pointCoordinates(Waypoint
&waypoint
)
105 QString data
= _reader
.readElementText();
106 const QChar
*sp
, *ep
, *cp
, *vp
;
112 sp
= data
.constData();
113 ep
= sp
+ data
.size();
115 for (cp
= sp
; cp
< ep
; cp
++)
119 for (vp
= cp
; cp
<= ep
; cp
++) {
124 val
[c
] = QString(vp
, cp
- vp
).toDouble(&res
);
130 } else if (cp
->isSpace() || cp
->isNull()) {
134 val
[c
] = QString(vp
, cp
- vp
).toDouble(&res
);
138 waypoint
.setCoordinates(Coordinates(val
[0], val
[1]));
139 if (!waypoint
.coordinates().isValid())
142 waypoint
.setElevation(val
[2]);
144 while (cp
->isSpace())
153 bool KMLParser::lineCoordinates(SegmentData
&segment
)
155 QString data
= _reader
.readElementText();
156 const QChar
*sp
, *ep
, *cp
, *vp
;
162 sp
= data
.constData();
163 ep
= sp
+ data
.size();
165 for (cp
= sp
; cp
< ep
; cp
++)
169 for (vp
= cp
; cp
<= ep
; cp
++) {
174 val
[c
] = QString(vp
, cp
- vp
).toDouble(&res
);
180 } else if (cp
->isSpace() || cp
->isNull()) {
184 val
[c
] = QString(vp
, cp
- vp
).toDouble(&res
);
188 segment
.append(Trackpoint(Coordinates(val
[0], val
[1])));
189 if (!segment
.last().coordinates().isValid())
192 segment
.last().setElevation(val
[2]);
194 while (cp
->isSpace())
204 bool KMLParser::polygonCoordinates(QVector
<Coordinates
> &points
)
206 QString data
= _reader
.readElementText();
207 const QChar
*sp
, *ep
, *cp
, *vp
;
213 sp
= data
.constData();
214 ep
= sp
+ data
.size();
216 for (cp
= sp
; cp
< ep
; cp
++)
220 for (vp
= cp
; cp
<= ep
; cp
++) {
225 val
[c
] = QString(vp
, cp
- vp
).toDouble(&res
);
231 } else if (cp
->isSpace() || cp
->isNull()) {
235 val
[c
] = QString(vp
, cp
- vp
).toDouble(&res
);
239 points
.append(Coordinates(val
[0], val
[1]));
240 if (!points
.last().isValid())
243 while (cp
->isSpace())
253 QDateTime
KMLParser::timeStamp()
257 while (_reader
.readNextStartElement()) {
258 if (_reader
.name() == QLatin1String("when"))
261 _reader
.skipCurrentElement();
267 void KMLParser::lineString(SegmentData
&segment
)
269 while (_reader
.readNextStartElement()) {
270 if (_reader
.name() == QLatin1String("coordinates")) {
271 if (!lineCoordinates(segment
))
272 _reader
.raiseError("Invalid coordinates");
274 _reader
.skipCurrentElement();
278 void KMLParser::linearRing(QVector
<Coordinates
> &coordinates
)
280 while (_reader
.readNextStartElement()) {
281 if (_reader
.name() == QLatin1String("coordinates")) {
282 if (!polygonCoordinates(coordinates
))
283 _reader
.raiseError("Invalid coordinates");
285 _reader
.skipCurrentElement();
289 void KMLParser::boundary(QVector
<Coordinates
> &coordinates
)
291 while (_reader
.readNextStartElement()) {
292 if (_reader
.name() == QLatin1String("LinearRing"))
293 linearRing(coordinates
);
295 _reader
.skipCurrentElement();
299 void KMLParser::polygon(Area
&area
)
303 while (_reader
.readNextStartElement()) {
304 QVector
<Coordinates
> path
;
306 if (_reader
.name() == QLatin1String("outerBoundaryIs")) {
307 if (!polygon
.isEmpty()) {
308 _reader
.raiseError("Multiple polygon outerBoundaryIss");
312 polygon
.append(path
);
313 } else if (_reader
.name() == QLatin1String("innerBoundaryIs")) {
314 if (polygon
.isEmpty()) {
315 _reader
.raiseError("Missing polygon outerBoundaryIs");
319 polygon
.append(path
);
321 _reader
.skipCurrentElement();
324 area
.append(polygon
);
327 void KMLParser::point(Waypoint
&waypoint
)
329 while (_reader
.readNextStartElement()) {
330 if (_reader
.name() == QLatin1String("coordinates")) {
331 if (!pointCoordinates(waypoint
))
332 _reader
.raiseError("Invalid coordinates");
334 _reader
.skipCurrentElement();
337 if (waypoint
.coordinates().isNull())
338 _reader
.raiseError("Missing Point coordinates");
341 void KMLParser::heartRate(SegmentData
&segment
)
344 const char error
[] = "Heartrate data count mismatch";
346 while (_reader
.readNextStartElement()) {
347 if (_reader
.name() == QLatin1String("value")) {
348 if (i
< segment
.size())
349 segment
[i
++].setHeartRate(number());
351 _reader
.raiseError(error
);
355 _reader
.skipCurrentElement();
358 if (!_reader
.error() && i
!= segment
.size())
359 _reader
.raiseError(error
);
362 void KMLParser::cadence(SegmentData
&segment
)
365 const char error
[] = "Cadence data count mismatch";
367 while (_reader
.readNextStartElement()) {
368 if (_reader
.name() == QLatin1String("value")) {
369 if (i
< segment
.size())
370 segment
[i
++].setCadence(number());
372 _reader
.raiseError(error
);
376 _reader
.skipCurrentElement();
379 if (!_reader
.error() && i
!= segment
.size())
380 _reader
.raiseError(error
);
383 void KMLParser::speed(SegmentData
&segment
)
386 const char error
[] = "Speed data count mismatch";
388 while (_reader
.readNextStartElement()) {
389 if (_reader
.name() == QLatin1String("value")) {
390 if (i
< segment
.size())
391 segment
[i
++].setSpeed(number());
393 _reader
.raiseError(error
);
397 _reader
.skipCurrentElement();
400 if (!_reader
.error() && i
!= segment
.size())
401 _reader
.raiseError(error
);
404 void KMLParser::temperature(SegmentData
&segment
)
407 const char error
[] = "Temperature data count mismatch";
409 while (_reader
.readNextStartElement()) {
410 if (_reader
.name() == QLatin1String("value")) {
411 if (i
< segment
.size())
412 segment
[i
++].setTemperature(number());
414 _reader
.raiseError(error
);
418 _reader
.skipCurrentElement();
421 if (!_reader
.error() && i
!= segment
.size())
422 _reader
.raiseError(error
);
425 void KMLParser::power(SegmentData
&segment
)
428 const char error
[] = "Power data count mismatch";
430 while (_reader
.readNextStartElement()) {
431 if (_reader
.name() == QLatin1String("value")) {
432 if (i
< segment
.size())
433 segment
[i
++].setPower(number());
435 _reader
.raiseError(error
);
439 _reader
.skipCurrentElement();
442 if (!_reader
.error() && i
!= segment
.size())
443 _reader
.raiseError(error
);
446 void KMLParser::schemaData(SegmentData
&segment
)
448 while (_reader
.readNextStartElement()) {
449 if (_reader
.name() == QLatin1String("SimpleArrayData")) {
450 QXmlStreamAttributes attr
= _reader
.attributes();
451 // There are files using capitalized names in the wild!
452 QString
name(attr
.value("name").toString().toLower());
454 if (name
== QLatin1String("heartrate"))
456 else if (name
== QLatin1String("cadence"))
458 else if (name
== QLatin1String("speed"))
460 else if (name
== QLatin1String("temperature"))
461 temperature(segment
);
462 else if (name
== QLatin1String("power"))
465 _reader
.skipCurrentElement();
467 _reader
.skipCurrentElement();
471 void KMLParser::extendedData(SegmentData
&segment
)
473 while (_reader
.readNextStartElement()) {
474 if (_reader
.name() == QLatin1String("SchemaData"))
477 _reader
.skipCurrentElement();
481 void KMLParser::track(SegmentData
&segment
)
483 const char error
[] = "gx:coord/when element count mismatch";
487 while (_reader
.readNextStartElement()) {
488 if (_reader
.name() == QLatin1String("when")) {
489 segment
.append(Trackpoint());
490 segment
.last().setTimestamp(time());
493 } else if (_reader
.name() == QLatin1String("coord")) {
494 if (i
== segment
.size()) {
495 _reader
.raiseError(error
);
497 } else if (!coord(segment
[i
])) {
498 _reader
.raiseError("Invalid coordinates");
501 if (segment
.at(i
).coordinates().isNull())
504 } else if (_reader
.name() == QLatin1String("ExtendedData"))
505 extendedData(segment
);
507 _reader
.skipCurrentElement();
510 if (i
!= segment
.size()) {
511 _reader
.raiseError(error
);
515 /* empty (invalid) coordinates are allowed per KML specification, but
516 invalid in our data representation so get rid of the segment entries */
518 SegmentData filtered
;
519 for (int i
= 0; i
< segment
.size(); i
++)
520 if (!segment
.at(i
).coordinates().isNull())
521 filtered
.append(segment
.at(i
));
526 void KMLParser::multiTrack(TrackData
&t
)
528 while (_reader
.readNextStartElement()) {
529 if (_reader
.name() == QLatin1String("Track")) {
530 t
.append(SegmentData());
533 _reader
.skipCurrentElement();
537 void KMLParser::photoOverlay(const Ctx
&ctx
, QVector
<Waypoint
> &waypoints
,
538 PointStyleMap
&pointStyles
, QMap
<QString
, QString
> &map
)
542 QMap
<QString
, PolygonStyle
> unused
;
543 QMap
<QString
, LineStyle
> unused2
;
544 static QRegularExpression
re("\\$\\[[^\\]]+\\]");
546 while (_reader
.readNextStartElement()) {
547 if (_reader
.name() == QLatin1String("name"))
548 w
.setName(_reader
.readElementText());
549 else if (_reader
.name() == QLatin1String("description"))
550 w
.setDescription(_reader
.readElementText());
551 else if (_reader
.name() == QLatin1String("phoneNumber"))
552 w
.setPhone(_reader
.readElementText());
553 else if (_reader
.name() == QLatin1String("address"))
554 w
.setAddress(_reader
.readElementText());
555 else if (_reader
.name() == QLatin1String("TimeStamp"))
556 w
.setTimestamp(timeStamp());
557 else if (_reader
.name() == QLatin1String("Style")) {
558 style(ctx
.dir
, pointStyles
, unused
, unused2
);
560 } else if (_reader
.name() == QLatin1String("StyleMap"))
562 else if (_reader
.name() == QLatin1String("Icon"))
564 else if (_reader
.name() == QLatin1String("Point"))
566 else if (_reader
.name() == QLatin1String("styleUrl"))
569 _reader
.skipCurrentElement();
572 if (!w
.coordinates().isNull()) {
573 PointStyleMap::iterator pit
= pointStyles
.find(id
);
574 if (pit
== pointStyles
.end())
575 pit
= pointStyles
.find(map
.value(id
));
576 w
.setStyle(pit
== pointStyles
.end()
577 ? PointStyle(QColor(0x55, 0x55, 0x55)) : *pit
);
579 img
.replace(re
, "0");
580 if (!QUrl(img
).scheme().isEmpty())
581 w
.addLink(Link(img
, "Photo Overlay"));
582 else if (ctx
.zip
&& Util::tempDir().isValid()) {
584 QByteArray
id(ctx
.path
.toUtf8() + img
.toUtf8());
585 QString
path(Util::tempDir().path() + "/" + QString("%0.%1")
586 .arg(QCryptographicHash::hash(id
, QCryptographicHash::Sha1
)
587 .toHex(), QString(fi
.suffix())));
588 QFile::rename(ctx
.dir
.absoluteFilePath(img
), path
);
591 w
.addImage(ctx
.dir
.absoluteFilePath(img
));
597 void KMLParser::multiGeometry(QList
<TrackData
> &tracks
, QList
<Area
> &areas
,
598 QVector
<Waypoint
> &waypoints
)
603 while (_reader
.readNextStartElement()) {
604 if (_reader
.name() == QLatin1String("Point")) {
605 waypoints
.append(Waypoint());
606 Waypoint
&w
= waypoints
.last();
608 } else if (_reader
.name() == QLatin1String("LineString")) {
610 tracks
.append(TrackData());
613 tp
->append(SegmentData());
614 lineString(tp
->last());
615 } else if (_reader
.name() == QLatin1String("Polygon")) {
617 areas
.append(Area());
622 _reader
.skipCurrentElement();
626 void KMLParser::placemark(const Ctx
&ctx
, QList
<TrackData
> &tracks
,
627 QList
<Area
> &areas
, QVector
<Waypoint
> &waypoints
, PointStyleMap
&pointStyles
,
628 PolygonStyleMap
&polyStyles
, LineStyleMap
&lineStyles
,
629 QMap
<QString
, QString
> &map
)
631 QString name
, desc
, phone
, address
, id
;
633 int trkIdx
= tracks
.size();
634 int wptIdx
= waypoints
.size();
635 int areaIdx
= areas
.size();
637 while (_reader
.readNextStartElement()) {
638 if (_reader
.name() == QLatin1String("name"))
639 name
= _reader
.readElementText();
640 else if (_reader
.name() == QLatin1String("description"))
641 desc
= _reader
.readElementText();
642 else if (_reader
.name() == QLatin1String("phoneNumber"))
643 phone
= _reader
.readElementText();
644 else if (_reader
.name() == QLatin1String("address"))
645 address
= _reader
.readElementText();
646 else if (_reader
.name() == QLatin1String("TimeStamp"))
647 timestamp
= timeStamp();
648 else if (_reader
.name() == QLatin1String("Style")) {
649 style(ctx
.dir
, pointStyles
, polyStyles
, lineStyles
);
651 } else if (_reader
.name() == QLatin1String("StyleMap"))
653 else if (_reader
.name() == QLatin1String("MultiGeometry"))
654 multiGeometry(tracks
, areas
, waypoints
);
655 else if (_reader
.name() == QLatin1String("Point")) {
656 waypoints
.append(Waypoint());
657 point(waypoints
.last());
658 } else if (_reader
.name() == QLatin1String("LineString")
659 || _reader
.name() == QLatin1String("LinearRing")) {
660 tracks
.append(TrackData());
661 tracks
.last().append(SegmentData());
662 lineString(tracks
.last().last());
663 } else if (_reader
.name() == QLatin1String("Track")) {
664 tracks
.append(TrackData());
665 tracks
.last().append(SegmentData());
666 track(tracks
.last().last());
667 } else if (_reader
.name() == QLatin1String("MultiTrack")) {
668 tracks
.append(TrackData());
669 multiTrack(tracks
.last());
670 } else if (_reader
.name() == QLatin1String("Polygon")) {
671 areas
.append(Area());
672 polygon(areas
.last());
673 } else if (_reader
.name() == QLatin1String("styleUrl"))
676 _reader
.skipCurrentElement();
679 PointStyleMap::iterator pit
= pointStyles
.find(id
);
680 if (pit
== pointStyles
.end())
681 pit
= pointStyles
.find(map
.value(id
));
682 LineStyleMap::iterator lit
= lineStyles
.find(id
);
683 if (lit
== lineStyles
.end())
684 lit
= lineStyles
.find(map
.value(id
));
685 PolygonStyleMap::iterator ait
= polyStyles
.find(id
);
686 if (ait
== polyStyles
.end())
687 ait
= polyStyles
.find(map
.value(id
));
689 for (int i
= wptIdx
; i
< waypoints
.size(); i
++) {
690 Waypoint
&w
= waypoints
[i
];
692 w
.setDescription(desc
);
693 w
.setTimestamp(timestamp
);
694 w
.setAddress(address
);
696 w
.setStyle(pit
== pointStyles
.end()
697 ? PointStyle(QColor(0x55, 0x55, 0x55)) : *pit
);
699 for (int i
= trkIdx
; i
< tracks
.size(); i
++) {
700 TrackData
&t
= tracks
[i
];
702 t
.setDescription(desc
);
703 t
.setStyle(lit
== lineStyles
.end()
704 ? LineStyle(QColor(0x55, 0x55, 0x55), 2, Qt::SolidLine
) : *lit
);
706 for (int i
= areaIdx
; i
< areas
.size(); i
++) {
709 a
.setDescription(desc
);
710 a
.setStyle(ait
== polyStyles
.end()
711 ? PolygonStyle(QColor(0x55, 0x55, 0x55, 0x99),
712 QColor(0x55, 0x55, 0x55, 0x99), 2) : *ait
);
716 QString
KMLParser::icon()
720 while (_reader
.readNextStartElement()) {
721 if (_reader
.name() == QLatin1String("href"))
722 path
= _reader
.readElementText();
724 _reader
.skipCurrentElement();
730 QColor
KMLParser::color()
732 QString
str(_reader
.readElementText());
736 bool aok
, bok
, gok
, rok
;
737 int a
= str
.mid(0, 2).toInt(&aok
, 16);
738 int b
= str
.mid(2, 2).toInt(&bok
, 16);
739 int g
= str
.mid(4, 2).toInt(&gok
, 16);
740 int r
= str
.mid(6, 2).toInt(&rok
, 16);
742 return (aok
&& bok
&& gok
&& rok
) ? QColor(r
, g
, b
, a
) : QColor();
745 QString
KMLParser::styleUrl()
747 QString
id(_reader
.readElementText());
748 return (id
.at(0) == '#') ? id
.right(id
.size() - 1) : QString();
751 void KMLParser::iconStyle(const QDir
&dir
, const QString
&id
,
752 PointStyleMap
&styles
)
755 QColor
c(0x55, 0x55, 0x55);
757 while (_reader
.readNextStartElement()) {
758 if (_reader
.name() == QLatin1String("Icon"))
759 img
= QPixmap(dir
.absoluteFilePath(icon()));
760 else if (_reader
.name() == QLatin1String("color"))
763 _reader
.skipCurrentElement();
766 styles
.insert(id
, PointStyle(img
, c
));
769 void KMLParser::polyStyle(const QString
&id
, PolygonStyleMap
&styles
)
771 QColor
c(0x55, 0x55, 0x55, 0x99);
772 uint fill
= 1, outline
= 1;
774 while (_reader
.readNextStartElement()) {
775 if (_reader
.name() == QLatin1String("color"))
777 else if (_reader
.name() == QLatin1String("fill"))
778 fill
= _reader
.readElementText().toUInt();
779 else if (_reader
.name() == QLatin1String("outline"))
780 outline
= _reader
.readElementText().toUInt();
782 _reader
.skipCurrentElement();
785 styles
.insert(id
, PolygonStyle(fill
? c
: QColor(),
786 outline
? c
: QColor(), 2));
789 void KMLParser::lineStyle(const QString
&id
, LineStyleMap
&styles
)
791 QColor
c(0x55, 0x55, 0x55);
794 while (_reader
.readNextStartElement()) {
795 if (_reader
.name() == QLatin1String("color"))
797 else if (_reader
.name() == QLatin1String("width"))
798 width
= _reader
.readElementText().toDouble();
800 _reader
.skipCurrentElement();
803 styles
.insert(id
, LineStyle(c
, width
, Qt::SolidLine
));
806 void KMLParser::styleMapPair(const QString
&id
, QMap
<QString
, QString
> &map
)
810 while (_reader
.readNextStartElement()) {
811 if (_reader
.name() == QLatin1String("key"))
812 key
= _reader
.readElementText();
813 else if (_reader
.name() == QLatin1String("styleUrl"))
816 _reader
.skipCurrentElement();
823 void KMLParser::styleMap(QMap
<QString
, QString
> &map
)
825 QString id
= _reader
.attributes().value("id").toString();
827 while (_reader
.readNextStartElement()) {
828 if (_reader
.name() == QLatin1String("Pair"))
829 styleMapPair(id
, map
);
831 _reader
.skipCurrentElement();
835 void KMLParser::style(const QDir
&dir
, PointStyleMap
&pointStyles
,
836 PolygonStyleMap
&polyStyles
, LineStyleMap
&lineStyles
)
838 QString id
= _reader
.attributes().value("id").toString();
840 while (_reader
.readNextStartElement()) {
841 if (_reader
.name() == QLatin1String("IconStyle"))
842 iconStyle(dir
, id
, pointStyles
);
843 else if (_reader
.name() == QLatin1String("PolyStyle"))
844 polyStyle(id
, polyStyles
);
845 else if (_reader
.name() == QLatin1String("LineStyle"))
846 lineStyle(id
, lineStyles
);
848 _reader
.skipCurrentElement();
852 void KMLParser::folder(const Ctx
&ctx
, QList
<TrackData
> &tracks
,
853 QList
<Area
> &areas
, QVector
<Waypoint
> &waypoints
,
854 PointStyleMap
&pointStyles
, PolygonStyleMap
&polyStyles
,
855 LineStyleMap
&lineStyles
, QMap
<QString
, QString
> &map
)
857 while (_reader
.readNextStartElement()) {
858 if (_reader
.name() == QLatin1String("Document"))
859 document(ctx
, tracks
, areas
, waypoints
);
860 else if (_reader
.name() == QLatin1String("Folder"))
861 folder(ctx
, tracks
, areas
, waypoints
, pointStyles
, polyStyles
,
863 else if (_reader
.name() == QLatin1String("Placemark"))
864 placemark(ctx
, tracks
, areas
, waypoints
, pointStyles
, polyStyles
,
866 else if (_reader
.name() == QLatin1String("PhotoOverlay"))
867 photoOverlay(ctx
, waypoints
, pointStyles
, map
);
869 _reader
.skipCurrentElement();
873 void KMLParser::document(const Ctx
&ctx
, QList
<TrackData
> &tracks
,
874 QList
<Area
> &areas
, QVector
<Waypoint
> &waypoints
)
876 PointStyleMap pointStyles
;
877 PolygonStyleMap polyStyles
;
878 LineStyleMap lineStyles
;
879 QMap
<QString
, QString
> map
;
881 while (_reader
.readNextStartElement()) {
882 if (_reader
.name() == QLatin1String("Document"))
883 document(ctx
, tracks
, areas
, waypoints
);
884 else if (_reader
.name() == QLatin1String("Folder"))
885 folder(ctx
, tracks
, areas
, waypoints
, pointStyles
, polyStyles
,
887 else if (_reader
.name() == QLatin1String("Placemark"))
888 placemark(ctx
, tracks
, areas
, waypoints
, pointStyles
, polyStyles
,
890 else if (_reader
.name() == QLatin1String("PhotoOverlay"))
891 photoOverlay(ctx
, waypoints
, pointStyles
, map
);
892 else if (_reader
.name() == QLatin1String("Style"))
893 style(ctx
.dir
, pointStyles
, polyStyles
, lineStyles
);
894 else if (_reader
.name() == QLatin1String("StyleMap"))
897 _reader
.skipCurrentElement();
901 void KMLParser::kml(const Ctx
&ctx
, QList
<TrackData
> &tracks
,
902 QList
<Area
> &areas
, QVector
<Waypoint
> &waypoints
)
904 PointStyleMap pointStyles
;
905 PolygonStyleMap polyStyles
;
906 LineStyleMap lineStyles
;
907 QMap
<QString
, QString
> map
;
909 while (_reader
.readNextStartElement()) {
910 if (_reader
.name() == QLatin1String("Document"))
911 document(ctx
, tracks
, areas
, waypoints
);
912 else if (_reader
.name() == QLatin1String("Folder"))
913 folder(ctx
, tracks
, areas
, waypoints
, pointStyles
, polyStyles
,
915 else if (_reader
.name() == QLatin1String("Placemark"))
916 placemark(ctx
, tracks
, areas
, waypoints
, pointStyles
, polyStyles
,
918 else if (_reader
.name() == QLatin1String("PhotoOverlay"))
919 photoOverlay(ctx
, waypoints
, pointStyles
, map
);
921 _reader
.skipCurrentElement();
925 bool KMLParser::parse(QFile
*file
, QList
<TrackData
> &tracks
,
926 QList
<RouteData
> &routes
, QList
<Area
> &areas
, QVector
<Waypoint
> &waypoints
)
934 QZipReader
zip(fi
.absoluteFilePath(), QIODevice::ReadOnly
);
935 QTemporaryDir tempDir
;
936 if (!tempDir
.isValid() || !zip
.extractAll(tempDir
.path()))
937 _reader
.raiseError("Error extracting ZIP file");
939 QDir
zipDir(tempDir
.path());
940 QFileInfoList
files(zipDir
.entryInfoList(QStringList("*.kml"),
944 _reader
.raiseError("No KML file found in ZIP file");
946 QFile
kmlFile(files
.first().absoluteFilePath());
947 if (!kmlFile
.open(QIODevice::ReadOnly
))
948 _reader
.raiseError("Error opening KML file");
950 _reader
.setDevice(&kmlFile
);
952 if (_reader
.readNextStartElement()) {
953 if (_reader
.name() == QLatin1String("kml"))
954 kml(Ctx(fi
.absoluteFilePath(), zipDir
, true),
955 tracks
, areas
, waypoints
);
957 _reader
.raiseError("Not a KML file");
964 _reader
.setDevice(file
);
966 if (_reader
.readNextStartElement()) {
967 if (_reader
.name() == QLatin1String("kml"))
968 kml(Ctx(fi
.absoluteFilePath(), fi
.absoluteDir(), false), tracks
,
971 _reader
.raiseError("Not a KML file");
975 return !_reader
.error();