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

Compare commits

..

No commits in common. "df8e8d76b8533c1bd2eb5e8751ac08e5f4e75642" and "cc8704ff20bd4b094102414e0506a6dc6ce31c3a" have entirely different histories.

3 changed files with 109 additions and 82 deletions

View File

@ -197,7 +197,6 @@ 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;
} }

View File

@ -1,6 +1,7 @@
#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
@ -9,6 +10,60 @@
#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;
@ -123,14 +178,22 @@ bool FITParser::skipValue(CTX &ctx, quint8 size)
bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header) bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
{ {
MessageDefinition *def = &(ctx.defs[header & 0x0f]); int local_id = header & 0x0f;
quint8 numFields; MessageDefinition *def = &(ctx.defs[local_id]);
quint8 i;
def->fields.clear();
def->devFields.clear(); if (def->fields) {
delete[] def->fields;
def->fields = 0;
}
if (def->devFields) {
delete[] def->devFields;
def->devFields = 0;
}
// reserved/unused // reserved/unused
if (!skipValue(ctx, 1)) if (!readValue(ctx, i))
return false; return false;
// endianness // endianness
@ -146,35 +209,40 @@ bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
if (!readValue(ctx, def->globalId)) if (!readValue(ctx, def->globalId))
return false; return false;
// definition records // number of records
if (!readValue(ctx, numFields)) if (!readValue(ctx, def->numFields))
return false; return false;
def->fields.resize(numFields); // definition records
for (int i = 0; i < def->fields.size(); i++) { def->fields = new Field[def->numFields];
if (!readData(ctx.file, (char*)&(def->fields[i]), sizeof(Field))) for (i = 0; i < def->numFields; i++) {
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(Field); ctx.len -= sizeof(def->fields[i]);
} }
// developer definition records // developer definition records
if (header & 0x20) { if (header & 0x20) {
if (!readValue(ctx, numFields)) if (!readValue(ctx, def->numDevFields))
return false; return false;
def->devFields.resize(numFields); def->devFields = new Field[def->numDevFields];
for (int i = 0; i < def->devFields.size(); i++) { for (i = 0; i < def->numDevFields; i++) {
if (!readData(ctx.file, (char*)&(def->devFields[i]), sizeof(Field))) static_assert(sizeof(def->fields[i]) == 3, "Invalid Field alignment");
if (!readData(ctx.file, (char*)&(def->devFields[i]),
sizeof(def->devFields[i])))
return false; return false;
ctx.len -= sizeof(Field); ctx.len -= sizeof(def->devFields[i]);
} }
} } else
def->numDevFields = 0;
return true; return true;
} }
bool FITParser::readField(CTX &ctx, const Field *field, QVariant &val, bool FITParser::readField(CTX &ctx, Field *field, QVariant &val, bool &valid)
bool &valid)
{ {
bool ret; bool ret;
@ -231,20 +299,22 @@ bool FITParser::readField(CTX &ctx, const Field *field, QVariant &val,
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->fields.size(); i++) { for (int i = 0; i < def->numFields; i++) {
const Field *field = &def->fields.at(i); field = &def->fields[i];
if (!readField(ctx, field, val, valid)) if (!readField(ctx, field, val, valid))
return false; return false;
if (!valid) if (!valid)
@ -346,9 +416,12 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
} }
} }
for (int i = 0; i < def->devFields.size(); i++) for (int i = 0; i < def->numDevFields; i++) {
if (!readField(ctx, &def->devFields.at(i), val, valid)) field = &def->devFields[i];
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) {
@ -380,15 +453,15 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
bool FITParser::parseDataMessage(CTX &ctx, quint8 header) bool FITParser::parseDataMessage(CTX &ctx, quint8 header)
{ {
int localId = header & 0xf; int local_id = header & 0xf;
MessageDefinition *def = &(ctx.defs[localId]); MessageDefinition *def = &(ctx.defs[local_id]);
return parseData(ctx, def); return parseData(ctx, def);
} }
bool FITParser::parseCompressedMessage(CTX &ctx, quint8 header) bool FITParser::parseCompressedMessage(CTX &ctx, quint8 header)
{ {
int localId = (header >> 5) & 3; int local_id = (header >> 5) & 3;
MessageDefinition *def = &(ctx.defs[localId]); MessageDefinition *def = &(ctx.defs[local_id]);
ctx.timestamp += header & 0x1f; ctx.timestamp += header & 0x1f;
return parseData(ctx, def); return parseData(ctx, def);
} }
@ -414,6 +487,7 @@ 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";
@ -441,6 +515,7 @@ 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;

View File

@ -3,72 +3,25 @@
#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 Event struct Field;
{ class MessageDefinition;
Event() : data(0), id(0), type(0) {} class CTX;
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, const Field *field, QVariant &val, bool &valid); bool readField(CTX &ctx, Field *field, QVariant &val, bool &valid);
bool parseHeader(CTX &ctx); bool parseHeader(CTX &ctx);
bool parseRecord(CTX &ctx); bool parseRecord(CTX &ctx);