4 #include "onmoveparsers.h"
7 static inline quint16
u16(const char *buffer
)
9 return qFromLittleEndian
<quint16
>(buffer
);
12 static inline qint16
s16(const char *buffer
)
14 return qFromLittleEndian
<qint16
>(buffer
);
17 static inline qint32
s32(const char *buffer
)
19 return qFromLittleEndian
<qint32
>(buffer
);
23 bool OMDParser::readHeaderFile(const QString
&omdPath
, Header
&hdr
)
25 QFileInfo
fi(omdPath
);
26 QString path
= fi
.absoluteDir().filePath(fi
.baseName() + ".OMH");
30 if (!file
.open(QIODevice::ReadOnly
)) {
31 qWarning("%s: %s", qPrintable(path
), qPrintable(file
.errorString()));
34 if (file
.read(buffer
, sizeof(buffer
)) != sizeof(buffer
)) {
35 qWarning("%s: invalid OMH file", qPrintable(path
));
39 quint8 Y
= buffer
[14];
40 quint8 M
= buffer
[15];
41 quint8 D
= buffer
[16];
42 quint8 h
= buffer
[17];
43 quint8 m
= buffer
[18];
44 quint16 ascent
= u16(buffer
+ 22);
45 quint16 descent
= u16(buffer
+ 24);
46 quint8 avgHr
= buffer
[12];
47 quint8 maxHr
= buffer
[13];
49 QDateTime
date(QDate(Y
+ 2000, M
, D
), QTime(h
, m
), Qt::UTC
);
50 if (!date
.isValid()) {
51 qWarning("%s: invalid date", qPrintable(path
));
56 hdr
.hr
= avgHr
|| maxHr
;
57 hdr
.elevation
= ascent
|| descent
;
62 bool OMDParser::readF1(const char *chunk
, const Header
&hdr
, Sequence
&seq
,
66 _errorString
= "invalid chunk sequence";
70 qint32 lat
= s32(chunk
);
71 qint32 lon
= s32(chunk
+ 4);
72 quint16 sec
= u16(chunk
+ 12);
73 quint8 fia
= chunk
[14];
74 qint16 alt
= s16(chunk
+ 15);
77 Trackpoint
t(Coordinates(lon
/ 1000000.0, lat
/ 1000000.0));
78 if (!t
.coordinates().isValid()) {
79 _errorString
= "invalid coordinates";
82 t
.setTimestamp(QDateTime(hdr
.date
.date(),
83 hdr
.date
.time().addSecs(sec
), Qt::UTC
));
87 seq
.idx
[seq
.cnt
] = segment
.size();
90 seq
.idx
[seq
.cnt
] = -1;
97 bool OMDParser::readF2(const char *chunk
, const Header
&hdr
, Sequence
&seq
,
101 _errorString
= "invalid chunk sequence";
105 quint16 speed1
= u16(chunk
+ 2);
106 quint8 hr1
= chunk
[6];
107 quint16 speed2
= u16(chunk
+ 12);
108 quint8 hr2
= chunk
[16];
110 if (seq
.idx
[0] >= 0) {
111 Trackpoint
&p0
= segment
[seq
.idx
[0]];
113 p0
.setHeartRate(hr1
);
114 p0
.setSpeed(speed1
/ 360.0);
116 if (seq
.idx
[1] >= 0) {
117 Trackpoint
&p1
= segment
[seq
.idx
[1]];
119 p1
.setHeartRate(hr2
);
120 p1
.setSpeed(speed2
/ 360.0);
130 bool OMDParser::parse(QFile
*file
, QList
<TrackData
> &tracks
,
131 QList
<RouteData
> &routes
, QList
<Area
> &polygons
, QVector
<Waypoint
> &waypoints
)
142 // If no header file is found or it is invalid, continue with the default
143 // header values. The track will have a fictional date and possibly some
144 // zero-graphs, but it will be still usable.
145 readHeaderFile(file
->fileName(), hdr
);
147 while ((size
= file
->read(chunk
, sizeof(chunk
))) == sizeof(chunk
)) {
148 switch ((quint8
)chunk
[19]) {
150 if (!readF1(chunk
, hdr
, seq
, segment
))
154 if (!readF2(chunk
, hdr
, seq
, segment
))
158 _errorString
= "invalid chunk type";
164 _errorString
= "I/O error";
167 _errorString
= "unexpected end of file";
171 tracks
.append(TrackData());
172 tracks
.last().append(segment
);
178 bool GHPParser::readHeaderFile(const QString
&ghpPath
, Header
&hdr
)
180 QFileInfo
fi(ghpPath
);
181 QString path
= fi
.absoluteDir().filePath(fi
.baseName() + ".GHT");
185 if (!file
.open(QIODevice::ReadOnly
)) {
186 qWarning("%s: %s", qPrintable(path
), qPrintable(file
.errorString()));
189 if (file
.read(buffer
, sizeof(buffer
)) != sizeof(buffer
)) {
190 qWarning("%s: invalid GHT file", qPrintable(path
));
194 quint8 Y
= buffer
[0];
195 quint8 M
= buffer
[1];
196 quint8 D
= buffer
[2];
197 quint8 h
= buffer
[3];
198 quint8 m
= buffer
[4];
199 quint8 s
= buffer
[5];
200 quint8 avgHr
= buffer
[61];
201 quint8 maxHr
= buffer
[60];
203 QDateTime
date(QDate(Y
+ 2000, M
, D
), QTime(h
, m
, s
), Qt::UTC
);
204 if (!date
.isValid()) {
205 qWarning("%s: invalid date", qPrintable(path
));
210 hdr
.hr
= avgHr
|| maxHr
;
215 bool GHPParser::readF0(const char *chunk
, const Header
&hdr
, int &time
,
216 SegmentData
&segment
)
218 qint32 lat
= s32(chunk
);
219 qint32 lon
= s32(chunk
+ 4);
220 qint16 alt
= s16(chunk
+ 8);
221 quint16 speed
= u16(chunk
+ 10);
222 quint8 hr
= chunk
[12];
223 quint8 fia
= chunk
[13];
224 qint32 ms
= s32(chunk
+ 16);
227 Trackpoint
t(Coordinates(lon
/ 1000000.0, lat
/ 1000000.0));
228 if (!t
.coordinates().isValid()) {
229 _errorString
= "invalid coordinates";
232 t
.setTimestamp(QDateTime(hdr
.date
.date(),
233 hdr
.date
.time().addMSecs(time
* 100), Qt::UTC
));
234 t
.setSpeed(speed
/ 360.0);
247 bool GHPParser::parse(QFile
*file
, QList
<TrackData
> &tracks
,
248 QList
<RouteData
> &routes
, QList
<Area
> &polygons
, QVector
<Waypoint
> &waypoints
)
260 readHeaderFile(file
->fileName(), hdr
);
262 while ((size
= file
->read(chunk
, sizeof(chunk
))) == sizeof(chunk
))
263 if (!readF0(chunk
, hdr
, time
, segment
))
267 _errorString
= "I/O error";
270 _errorString
= "unexpected end of file";
273 if (!segment
.size()) {
274 _errorString
= "No usable data found";
278 tracks
.append(TrackData());
279 tracks
.last().append(segment
);