mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-27 21:24:47 +01:00
Compare commits
2 Commits
cc8704ff20
...
df8e8d76b8
Author | SHA1 | Date | |
---|---|---|---|
df8e8d76b8 | |||
1034c52b39 |
@ -197,6 +197,7 @@ bool Downloader::doDownload(const Download &dl, const QList<HTTPHeader> &headers
|
|||||||
if (!file->open(QIODevice::WriteOnly)) {
|
if (!file->open(QIODevice::WriteOnly)) {
|
||||||
qWarning("%s: %s", qPrintable(file->fileName()),
|
qWarning("%s: %s", qPrintable(file->fileName()),
|
||||||
qPrintable(file->errorString()));
|
qPrintable(file->errorString()));
|
||||||
|
delete file;
|
||||||
_errorDownloads.insert(url, RETRIES);
|
_errorDownloads.insert(url, RETRIES);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <QtEndian>
|
#include <QtEndian>
|
||||||
#include "fitparser.h"
|
#include "fitparser.h"
|
||||||
|
|
||||||
|
|
||||||
#define FIT_MAGIC 0x5449462E // .FIT
|
#define FIT_MAGIC 0x5449462E // .FIT
|
||||||
|
|
||||||
#define RECORD_MESSAGE 20
|
#define RECORD_MESSAGE 20
|
||||||
@ -10,60 +9,6 @@
|
|||||||
#define COURSE_POINT 32
|
#define COURSE_POINT 32
|
||||||
#define TIMESTAMP_FIELD 253
|
#define TIMESTAMP_FIELD 253
|
||||||
|
|
||||||
class Event {
|
|
||||||
public:
|
|
||||||
Event() : id(0), type(0), data(0) {}
|
|
||||||
|
|
||||||
quint8 id;
|
|
||||||
quint8 type;
|
|
||||||
quint32 data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileHeader {
|
|
||||||
quint8 headerSize;
|
|
||||||
quint8 protocolVersion;
|
|
||||||
quint16 profileVersion;
|
|
||||||
quint32 dataSize;
|
|
||||||
quint32 magic;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FITParser::Field {
|
|
||||||
quint8 id;
|
|
||||||
quint8 size;
|
|
||||||
quint8 type;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FITParser::MessageDefinition {
|
|
||||||
public:
|
|
||||||
MessageDefinition() : endian(0), globalId(0), numFields(0), fields(0),
|
|
||||||
numDevFields(0), devFields(0) {}
|
|
||||||
~MessageDefinition() {delete[] fields; delete[] devFields;}
|
|
||||||
|
|
||||||
quint8 endian;
|
|
||||||
quint16 globalId;
|
|
||||||
quint8 numFields;
|
|
||||||
Field *fields;
|
|
||||||
quint8 numDevFields;
|
|
||||||
Field *devFields;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FITParser::CTX {
|
|
||||||
public:
|
|
||||||
CTX(QFile *file, QVector<Waypoint> &waypoints)
|
|
||||||
: file(file), waypoints(waypoints), len(0), endian(0), timestamp(0),
|
|
||||||
ratio(NAN) {}
|
|
||||||
|
|
||||||
QFile *file;
|
|
||||||
QVector<Waypoint> &waypoints;
|
|
||||||
quint32 len;
|
|
||||||
quint8 endian;
|
|
||||||
quint32 timestamp;
|
|
||||||
MessageDefinition defs[16];
|
|
||||||
qreal ratio;
|
|
||||||
Trackpoint trackpoint;
|
|
||||||
SegmentData segment;
|
|
||||||
};
|
|
||||||
|
|
||||||
static QMap<int, QString> coursePointSymbolsInit()
|
static QMap<int, QString> coursePointSymbolsInit()
|
||||||
{
|
{
|
||||||
QMap<int, QString> map;
|
QMap<int, QString> map;
|
||||||
@ -178,22 +123,14 @@ bool FITParser::skipValue(CTX &ctx, quint8 size)
|
|||||||
|
|
||||||
bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
|
bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
|
||||||
{
|
{
|
||||||
int local_id = header & 0x0f;
|
MessageDefinition *def = &(ctx.defs[header & 0x0f]);
|
||||||
MessageDefinition *def = &(ctx.defs[local_id]);
|
quint8 numFields;
|
||||||
quint8 i;
|
|
||||||
|
|
||||||
|
def->fields.clear();
|
||||||
if (def->fields) {
|
def->devFields.clear();
|
||||||
delete[] def->fields;
|
|
||||||
def->fields = 0;
|
|
||||||
}
|
|
||||||
if (def->devFields) {
|
|
||||||
delete[] def->devFields;
|
|
||||||
def->devFields = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reserved/unused
|
// reserved/unused
|
||||||
if (!readValue(ctx, i))
|
if (!skipValue(ctx, 1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// endianness
|
// endianness
|
||||||
@ -209,40 +146,35 @@ bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
|
|||||||
if (!readValue(ctx, def->globalId))
|
if (!readValue(ctx, def->globalId))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// number of records
|
// definition records
|
||||||
if (!readValue(ctx, def->numFields))
|
if (!readValue(ctx, numFields))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// definition records
|
def->fields.resize(numFields);
|
||||||
def->fields = new Field[def->numFields];
|
for (int i = 0; i < def->fields.size(); i++) {
|
||||||
for (i = 0; i < def->numFields; i++) {
|
if (!readData(ctx.file, (char*)&(def->fields[i]), sizeof(Field)))
|
||||||
static_assert(sizeof(def->fields[i]) == 3, "Invalid Field alignment");
|
|
||||||
if (!readData(ctx.file, (char*)&(def->fields[i]),
|
|
||||||
sizeof(def->fields[i])))
|
|
||||||
return false;
|
return false;
|
||||||
ctx.len -= sizeof(def->fields[i]);
|
ctx.len -= sizeof(Field);
|
||||||
}
|
}
|
||||||
|
|
||||||
// developer definition records
|
// developer definition records
|
||||||
if (header & 0x20) {
|
if (header & 0x20) {
|
||||||
if (!readValue(ctx, def->numDevFields))
|
if (!readValue(ctx, numFields))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
def->devFields = new Field[def->numDevFields];
|
def->devFields.resize(numFields);
|
||||||
for (i = 0; i < def->numDevFields; i++) {
|
for (int i = 0; i < def->devFields.size(); i++) {
|
||||||
static_assert(sizeof(def->fields[i]) == 3, "Invalid Field alignment");
|
if (!readData(ctx.file, (char*)&(def->devFields[i]), sizeof(Field)))
|
||||||
if (!readData(ctx.file, (char*)&(def->devFields[i]),
|
|
||||||
sizeof(def->devFields[i])))
|
|
||||||
return false;
|
return false;
|
||||||
ctx.len -= sizeof(def->devFields[i]);
|
ctx.len -= sizeof(Field);
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
def->numDevFields = 0;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FITParser::readField(CTX &ctx, Field *field, QVariant &val, bool &valid)
|
bool FITParser::readField(CTX &ctx, const Field *field, QVariant &val,
|
||||||
|
bool &valid)
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
@ -299,22 +231,20 @@ bool FITParser::readField(CTX &ctx, Field *field, QVariant &val, bool &valid)
|
|||||||
|
|
||||||
bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||||
{
|
{
|
||||||
Field *field;
|
|
||||||
QVariant val;
|
QVariant val;
|
||||||
bool valid;
|
bool valid;
|
||||||
Event event;
|
Event event;
|
||||||
Waypoint waypoint;
|
Waypoint waypoint;
|
||||||
|
|
||||||
|
if (!def->fields.size() && !def->devFields.size()) {
|
||||||
if (!def->fields && !def->devFields) {
|
|
||||||
_errorString = "Undefined data message";
|
_errorString = "Undefined data message";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.endian = def->endian;
|
ctx.endian = def->endian;
|
||||||
|
|
||||||
for (int i = 0; i < def->numFields; i++) {
|
for (int i = 0; i < def->fields.size(); i++) {
|
||||||
field = &def->fields[i];
|
const Field *field = &def->fields.at(i);
|
||||||
if (!readField(ctx, field, val, valid))
|
if (!readField(ctx, field, val, valid))
|
||||||
return false;
|
return false;
|
||||||
if (!valid)
|
if (!valid)
|
||||||
@ -416,12 +346,9 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < def->numDevFields; i++) {
|
for (int i = 0; i < def->devFields.size(); i++)
|
||||||
field = &def->devFields[i];
|
if (!readField(ctx, &def->devFields.at(i), val, valid))
|
||||||
if (!readField(ctx, field, val, valid))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (def->globalId == EVENT_MESSAGE) {
|
if (def->globalId == EVENT_MESSAGE) {
|
||||||
if ((event.id == 42 || event.id == 43) && event.type == 3) {
|
if ((event.id == 42 || event.id == 43) && event.type == 3) {
|
||||||
@ -453,15 +380,15 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
|
|
||||||
bool FITParser::parseDataMessage(CTX &ctx, quint8 header)
|
bool FITParser::parseDataMessage(CTX &ctx, quint8 header)
|
||||||
{
|
{
|
||||||
int local_id = header & 0xf;
|
int localId = header & 0xf;
|
||||||
MessageDefinition *def = &(ctx.defs[local_id]);
|
MessageDefinition *def = &(ctx.defs[localId]);
|
||||||
return parseData(ctx, def);
|
return parseData(ctx, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FITParser::parseCompressedMessage(CTX &ctx, quint8 header)
|
bool FITParser::parseCompressedMessage(CTX &ctx, quint8 header)
|
||||||
{
|
{
|
||||||
int local_id = (header >> 5) & 3;
|
int localId = (header >> 5) & 3;
|
||||||
MessageDefinition *def = &(ctx.defs[local_id]);
|
MessageDefinition *def = &(ctx.defs[localId]);
|
||||||
ctx.timestamp += header & 0x1f;
|
ctx.timestamp += header & 0x1f;
|
||||||
return parseData(ctx, def);
|
return parseData(ctx, def);
|
||||||
}
|
}
|
||||||
@ -487,7 +414,6 @@ bool FITParser::parseHeader(CTX &ctx)
|
|||||||
quint16 crc;
|
quint16 crc;
|
||||||
qint64 len;
|
qint64 len;
|
||||||
|
|
||||||
static_assert(sizeof(hdr) == 12, "Invalid FileHeader alignment");
|
|
||||||
len = ctx.file->read((char*)&hdr, sizeof(hdr));
|
len = ctx.file->read((char*)&hdr, sizeof(hdr));
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
_errorString = "I/O error";
|
_errorString = "I/O error";
|
||||||
@ -515,7 +441,6 @@ bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
Q_UNUSED(polygons);
|
Q_UNUSED(polygons);
|
||||||
CTX ctx(file, waypoints);
|
CTX ctx(file, waypoints);
|
||||||
|
|
||||||
|
|
||||||
if (!parseHeader(ctx))
|
if (!parseHeader(ctx))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -3,25 +3,72 @@
|
|||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
class QFile;
|
|
||||||
|
|
||||||
class FITParser : public Parser
|
class FITParser : public Parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
FITParser()
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Field) == 3, "Invalid Field alignment");
|
||||||
|
static_assert(sizeof(FileHeader) == 12, "Invalid FileHeader alignment");
|
||||||
|
}
|
||||||
|
|
||||||
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
|
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
|
||||||
QList<Area> &polygons, QVector<Waypoint> &waypoints);
|
QList<Area> &polygons, QVector<Waypoint> &waypoints);
|
||||||
QString errorString() const {return _errorString;}
|
QString errorString() const {return _errorString;}
|
||||||
int errorLine() const {return 0;}
|
int errorLine() const {return 0;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Field;
|
struct Event
|
||||||
class MessageDefinition;
|
{
|
||||||
class CTX;
|
Event() : data(0), id(0), type(0) {}
|
||||||
|
|
||||||
|
quint32 data;
|
||||||
|
quint8 id;
|
||||||
|
quint8 type;
|
||||||
|
};
|
||||||
|
struct FileHeader
|
||||||
|
{
|
||||||
|
quint8 headerSize;
|
||||||
|
quint8 protocolVersion;
|
||||||
|
quint16 profileVersion;
|
||||||
|
quint32 dataSize;
|
||||||
|
quint32 magic;
|
||||||
|
};
|
||||||
|
struct Field
|
||||||
|
{
|
||||||
|
quint8 id;
|
||||||
|
quint8 size;
|
||||||
|
quint8 type;
|
||||||
|
};
|
||||||
|
struct MessageDefinition
|
||||||
|
{
|
||||||
|
MessageDefinition() : globalId(0), endian(0) {}
|
||||||
|
|
||||||
|
QVector<Field> fields;
|
||||||
|
QVector<Field> devFields;
|
||||||
|
quint16 globalId;
|
||||||
|
quint8 endian;
|
||||||
|
};
|
||||||
|
struct CTX {
|
||||||
|
CTX(QFile *file, QVector<Waypoint> &waypoints)
|
||||||
|
: file(file), waypoints(waypoints), len(0), endian(0), timestamp(0),
|
||||||
|
ratio(NAN) {}
|
||||||
|
|
||||||
|
QFile *file;
|
||||||
|
QVector<Waypoint> &waypoints;
|
||||||
|
quint32 len;
|
||||||
|
quint8 endian;
|
||||||
|
quint32 timestamp;
|
||||||
|
MessageDefinition defs[16];
|
||||||
|
qreal ratio;
|
||||||
|
Trackpoint trackpoint;
|
||||||
|
SegmentData segment;
|
||||||
|
};
|
||||||
|
|
||||||
bool readData(QFile *file, char *data, size_t size);
|
bool readData(QFile *file, char *data, size_t size);
|
||||||
template<class T> bool readValue(CTX &ctx, T &val);
|
template<class T> bool readValue(CTX &ctx, T &val);
|
||||||
bool skipValue(CTX &ctx, quint8 size);
|
bool skipValue(CTX &ctx, quint8 size);
|
||||||
bool readField(CTX &ctx, Field *field, QVariant &val, bool &valid);
|
bool readField(CTX &ctx, const Field *field, QVariant &val, bool &valid);
|
||||||
|
|
||||||
bool parseHeader(CTX &ctx);
|
bool parseHeader(CTX &ctx);
|
||||||
bool parseRecord(CTX &ctx);
|
bool parseRecord(CTX &ctx);
|
||||||
|
Loading…
Reference in New Issue
Block a user