2 #include "common/util.h"
6 static bool readLat(const char *data
, qreal
&lat
)
8 int d
= Util::str2int(data
, 2);
9 int mi
= Util::str2int(data
+ 2, 2);
10 int mf
= Util::str2int(data
+ 4, 3);
11 if (d
< 0 || mi
< 0 || mf
< 0)
14 if (!(data
[7] == 'N' || data
[7] == 'S'))
17 lat
= d
+ (((qreal
)mi
+ (qreal
)mf
/1000) / 60);
27 static bool readLon(const char *data
, qreal
&lon
)
29 int d
= Util::str2int(data
, 3);
30 int mi
= Util::str2int(data
+ 3, 2);
31 int mf
= Util::str2int(data
+ 5, 3);
32 if (d
< 0 || mi
< 0 || mf
< 0)
35 if (!(data
[8] == 'E' || data
[8] == 'W'))
38 lon
= d
+ (((qreal
)mi
+ (qreal
)mf
/1000) / 60);
48 static bool readAltitude(const char *data
, qreal
&ele
)
52 if (!(data
[0] == 'A' || data
[0] == 'V'))
56 if ((ga
= Util::str2int(data
+ 7, 4)) < 0)
60 if ((ga
= Util::str2int(data
+ 6, 5)) < 0)
72 static bool readTimestamp(const char *data
, QTime
&time
)
74 int h
= Util::str2int(data
, 2);
75 int m
= Util::str2int(data
+ 2, 2);
76 int s
= Util::str2int(data
+ 4, 2);
78 if (h
< 0 || m
< 0 || s
< 0)
81 time
= QTime(h
, m
, s
);
88 static bool readARecord(const char *line
, qint64 len
)
90 /* The minimal A record length should be 7 according to the specification,
91 but records with length of 6 exist in the wild */
92 if (len
< 6 || line
[0] != 'A')
95 for (int i
= 1; i
< 6; i
++)
96 if (!::isprint(line
[i
]))
101 bool IGCParser::readHRecord(CTX
&ctx
, const char *line
, int len
)
103 if (len
< 11 || ::strncmp(line
, "HFDTE", 5))
106 int offset
= (len
< 16 || ::strncmp(line
+ 5, "DATE:", 5)) ? 5 : 10;
108 int d
= Util::str2int(line
+ offset
, 2);
109 int m
= Util::str2int(line
+ offset
+ 2, 2);
110 int y
= Util::str2int(line
+ offset
+ 4, 2);
112 if (y
< 0 || m
< 0 || d
< 0) {
113 _errorString
= "Invalid date header format";
117 ctx
.date
= QDate(y
+ 2000 <= QDate::currentDate().year()
118 ? 2000 + y
: 1900 + y
, m
, d
);
119 if (!ctx
.date
.isValid()) {
120 _errorString
= "Invalid date";
127 bool IGCParser::readBRecord(CTX
&ctx
, const char *line
, int len
,
128 SegmentData
&segment
)
138 if (!readTimestamp(line
+ 1, time
)) {
139 _errorString
= "Invalid timestamp";
143 if (!readLat(line
+ 7, lat
)) {
144 _errorString
= "Invalid latitude";
147 if (!readLon(line
+ 15, lon
)) {
148 _errorString
= "Invalid longitude";
152 if (!readAltitude(line
+ 24, ele
)) {
153 _errorString
= "Invalid altitude";
157 if (time
< ctx
.time
&& !segment
.isEmpty()
158 && ctx
.date
== segment
.last().timestamp().date())
159 ctx
.date
= ctx
.date
.addDays(1);
162 Trackpoint
t(Coordinates(lon
, lat
));
163 t
.setTimestamp(QDateTime(ctx
.date
, ctx
.time
, Qt::UTC
));
170 bool IGCParser::readCRecord(const char *line
, int len
, RouteData
&route
)
178 if (!readLat(line
+ 1, lat
)) {
179 _errorString
= "Invalid latitude";
182 if (!readLon(line
+ 9, lon
)) {
183 _errorString
= "Invalid longitude";
187 if (!(lat
== 0 && lon
== 0)) {
188 QByteArray
ba(line
+ 18, len
- 19);
190 Waypoint
w(Coordinates(lon
, lat
));
191 w
.setName(QString(ba
.trimmed()));
198 bool IGCParser::parse(QFile
*file
, QList
<TrackData
> &tracks
,
199 QList
<RouteData
> &routes
, QList
<Area
> &polygons
,
200 QVector
<Waypoint
> &waypoints
)
205 char line
[76 + 2 + 1 + 1];
206 bool route
= false, track
= false;
211 _errorString
.clear();
213 while (!file
->atEnd()) {
214 len
= file
->readLine(line
, sizeof(line
));
217 _errorString
= "I/O error";
219 } else if (len
> (qint64
)sizeof(line
) - 1) {
220 _errorString
= "Line limit exceeded";
224 if (_errorLine
== 1) {
225 if (!readARecord(line
, len
)) {
226 _errorString
= "Invalid/missing A record";
230 if (line
[0] == 'H') {
231 if (!readHRecord(ctx
, line
, len
))
233 } else if (line
[0] == 'C') {
235 if (!readCRecord(line
, len
, routes
.last()))
239 routes
.append(RouteData());
241 } else if (line
[0] == 'B') {
242 if (ctx
.date
.isNull()) {
243 /* The date H header is mandatory, but XCSOAR generates
244 files without it, so add a dummy date in such case */
245 qWarning("%s: Missing date header",
246 qPrintable(file
->fileName()));
247 ctx
.date
= QDate(1970, 1, 1);
250 tracks
.append(SegmentData());
251 ctx
.time
= QTime(0, 0);
254 if (!readBRecord(ctx
, line
, len
, tracks
.last().last()))