1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 13:41:16 +01:00

Do not duplicate temporary images + improved error handling

This commit is contained in:
Martin Tůma 2019-11-07 23:23:25 +01:00
parent 9e63e3f47e
commit 3632ed8816
2 changed files with 147 additions and 151 deletions

View File

@ -6,6 +6,7 @@
#include <QApplication> #include <QApplication>
#include <QBuffer> #include <QBuffer>
#include <QImageReader> #include <QImageReader>
#include <QCryptographicHash>
#include <QTemporaryDir> #include <QTemporaryDir>
#include "gpiparser.h" #include "gpiparser.h"
@ -109,7 +110,6 @@ qint64 CryptDevice::readData(char *data, qint64 maxSize)
return ts; return ts;
} }
static int cnt = 0;
static const QTemporaryDir &tempDir() static const QTemporaryDir &tempDir()
{ {
@ -125,7 +125,12 @@ static inline double toWGS(qint32 v)
static quint16 nextHeaderType(QDataStream &stream) static quint16 nextHeaderType(QDataStream &stream)
{ {
quint16 type = 0; quint16 type = 0;
stream.device()->peek((char*)&type, sizeof(type));
if (stream.device()->peek((char*)&type, sizeof(type))
< (qint64)sizeof(type)) {
stream.setStatus(QDataStream::ReadCorruptData);
return 0xFFFF;
} else
return qFromLittleEndian(type); return qFromLittleEndian(type);
} }
@ -146,18 +151,6 @@ static quint32 skipRecord(QDataStream &stream)
return rs + rh.size; return rs + rh.size;
} }
static quint32 readFprsRecord(QDataStream &stream)
{
RecordHeader rh;
quint16 s1;
quint8 rs, s2, s3, s4;
rs = readRecordHeader(stream, rh);
stream >> s1 >> s2 >> s3 >> s4;
return rs + 5;
}
static quint16 readString(QDataStream &stream, QTextCodec *codec, QString &str) static quint16 readString(QDataStream &stream, QTextCodec *codec, QString &str)
{ {
quint16 len; quint16 len;
@ -180,7 +173,7 @@ static quint32 readTranslatedObjects(QDataStream &stream, QTextCodec *codec,
stream >> size; stream >> size;
ret = size + 4; ret = size + 4;
while (size > 0) { while (stream.status() == QDataStream::Ok && size > 0) {
QString str; QString str;
stream.readRawData(lang, sizeof(lang)); stream.readRawData(lang, sizeof(lang));
size -= readString(stream, codec, str) + 2; size -= readString(stream, codec, str) + 2;
@ -193,6 +186,67 @@ static quint32 readTranslatedObjects(QDataStream &stream, QTextCodec *codec,
return ret; return ret;
} }
static quint32 readFprsRecord(QDataStream &stream)
{
RecordHeader rh;
quint16 s1;
quint8 rs, s2, s3, s4;
rs = readRecordHeader(stream, rh);
stream >> s1 >> s2 >> s3 >> s4;
return rs + 5;
}
static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec)
{
RecordHeader rh;
quint32 ds, s1;
quint16 s2, s3;
quint8 rs;
QList<TranslatedString> obj;
rs = readRecordHeader(stream, rh);
stream >> s1 >> s2 >> s3;
ds = 8;
ds += readTranslatedObjects(stream, codec, obj);
ds += readTranslatedObjects(stream, codec, obj);
if (s1 & 0x10) {
quint8 ss1, ss2;
quint16 ss3;
stream >> ss1 >> ss2 >> ss3;
ds += 4;
}
if (s1 & 0x100) {
quint32 ss1;
stream >> ss1;
if (ss1)
stream.skipRawData(ss1);
ds += ss1 + 4;
}
if (s1 & 0x400) {
QString str;
ds += readString(stream, codec, str);
}
if (s1 & 0x400000) {
quint16 ss1;
stream >> ss1;
if (ss1)
stream.skipRawData(ss1);
ds += ss1 + 2;
}
// structure of higher fields not known
if (ds > rh.size)
stream.setStatus(QDataStream::ReadCorruptData);
else if (ds < rh.size)
// skip remaining unknown fields
stream.skipRawData(rh.size - ds);
return rs + rh.size;
}
static quint32 readDescription(QDataStream &stream, QTextCodec *codec, static quint32 readDescription(QDataStream &stream, QTextCodec *codec,
Waypoint &waypoint) Waypoint &waypoint)
{ {
@ -276,7 +330,8 @@ static quint32 readContact(QDataStream &stream, QTextCodec *codec,
return rs + rh.size; return rs + rh.size;
} }
static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint) static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint,
const QString &fileName, int &imgId)
{ {
RecordHeader rh; RecordHeader rh;
quint8 rs, s1; quint8 rs, s1;
@ -292,7 +347,9 @@ static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint)
QBuffer buf(&ba); QBuffer buf(&ba);
QImageReader ir(&buf); QImageReader ir(&buf);
QFile imgFile(tempDir().filePath(QString("%0.%1").arg(QString::number(cnt++), QByteArray id(fileName.toUtf8() + QByteArray::number(imgId++));
QFile imgFile(tempDir().filePath(QString("%0.%1").arg(
QCryptographicHash::hash(id, QCryptographicHash::Sha1).toHex(),
QString(ir.format())))); QString(ir.format()))));
imgFile.open(QIODevice::WriteOnly); imgFile.open(QIODevice::WriteOnly);
imgFile.write(ba); imgFile.write(ba);
@ -307,7 +364,7 @@ static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint)
} }
static quint32 readPOI(QDataStream &stream, QTextCodec *codec, static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints) QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
{ {
RecordHeader rh; RecordHeader rh;
quint8 rs; quint8 rs;
@ -326,7 +383,7 @@ static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
if (!obj.isEmpty()) if (!obj.isEmpty())
waypoints.last().setName(obj.first().str()); waypoints.last().setName(obj.first().str());
while (ds < rh.size) { while (stream.status() == QDataStream::Ok && ds < rh.size) {
switch(nextHeaderType(stream)) { switch(nextHeaderType(stream)) {
case 10: case 10:
ds += readDescription(stream, codec, waypoints.last()); ds += readDescription(stream, codec, waypoints.last());
@ -335,7 +392,7 @@ static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
ds += readContact(stream, codec, waypoints.last()); ds += readContact(stream, codec, waypoints.last());
break; break;
case 13: case 13:
ds += readImageInfo(stream, waypoints.last()); ds += readImageInfo(stream, waypoints.last(), fileName, imgId);
break; break;
case 14: case 14:
ds += readNotes(stream, codec, waypoints.last()); ds += readNotes(stream, codec, waypoints.last());
@ -352,7 +409,7 @@ static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
} }
static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec, static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints) QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
{ {
RecordHeader rh; RecordHeader rh;
quint32 ds, s5; quint32 ds, s5;
@ -365,13 +422,14 @@ static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
stream.skipRawData(s6); stream.skipRawData(s6);
ds = 22 + s6; ds = 22 + s6;
if (rh.flags & 0x8) { if (rh.flags & 0x8) {
while (ds < rh.size) { while (stream.status() == QDataStream::Ok && ds < rh.size) {
switch(nextHeaderType(stream)) { switch(nextHeaderType(stream)) {
case 2: case 2:
ds += readPOI(stream, codec, waypoints); ds += readPOI(stream, codec, waypoints, fileName, imgId);
break; break;
case 8: case 8:
ds += readSpatialIndex(stream, codec, waypoints); ds += readSpatialIndex(stream, codec, waypoints, fileName,
imgId);
break; break;
default: default:
ds += skipRecord(stream); ds += skipRecord(stream);
@ -385,82 +443,54 @@ static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
return rs + rh.size; return rs + rh.size;
} }
static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec) static void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
{ {
RecordHeader rh; RecordHeader rh;
quint32 ds, s1;
quint16 s2, s3;
quint8 rs;
QList<TranslatedString> obj; QList<TranslatedString> obj;
quint32 ds;
rs = readRecordHeader(stream, rh);
stream >> s1 >> s2 >> s3;
ds = 8;
ds += readTranslatedObjects(stream, codec, obj);
ds += readTranslatedObjects(stream, codec, obj);
if (s1 & 0x10) {
quint8 ss1, ss2;
quint16 ss3;
stream >> ss1 >> ss2 >> ss3;
ds += 4;
}
if (s1 & 0x100) {
quint32 ss1;
stream >> ss1;
if (ss1)
stream.skipRawData(ss1);
ds += ss1 + 4;
}
if (s1 & 0x400) {
QString str;
ds += readString(stream, codec, str);
}
if (s1 & 0x400000) {
quint16 ss1;
stream >> ss1;
if (ss1)
stream.skipRawData(ss1);
ds += ss1 + 2;
}
// structure of higher fields not known
if (ds > rh.size)
stream.setStatus(QDataStream::ReadCorruptData);
else if (ds < rh.size)
// skip remaining unknown fields
stream.skipRawData(rh.size - ds);
return rs + rh.size;
}
bool GPIParser::readFileHeader(QDataStream &stream, quint32 &ebs)
{
RecordHeader rh;
quint32 ds, s7;
quint16 s10;
quint8 s5, s6, s8, s9;
char magic[6];
readRecordHeader(stream, rh); readRecordHeader(stream, rh);
stream.readRawData(magic, sizeof(magic)); ds = readTranslatedObjects(stream, codec, obj);
if (memcmp(magic, "GRMREC", sizeof(magic))) { ds += readSpatialIndex(stream, codec, waypoints, fileName, imgId);
_errorString = "Not a GPI file"; if (rh.flags & 0x8) {
return false; while (stream.status() == QDataStream::Ok && ds < rh.size) {
switch(nextHeaderType(stream)) {
case 5: // symbol
case 7: // category
default:
ds += skipRecord(stream);
}
}
} }
stream >> s5 >> s6 >> s7 >> s8 >> s9 >> s10;
stream.skipRawData(s10);
ds = sizeof(magic) + 10 + s10;
if (rh.flags & 8)
ds += readFprsRecord(stream);
ebs = (s8 & 0x4) ? s9 * 8 + 8 : 0; if (ds != rh.size)
stream.setStatus(QDataStream::ReadCorruptData);
}
if (stream.status() != QDataStream::Ok || ds != rh.size) { bool GPIParser::readData(QDataStream &stream, QTextCodec *codec,
_errorString = "Invalid file header"; QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
return false; {
} else while (stream.status() == QDataStream::Ok) {
switch (nextHeaderType(stream)) {
case 0x09: // POI database
readPOIDatabase(stream, codec, waypoints, fileName, imgId);
break;
case 0xffff: // EOF
skipRecord(stream);
if (stream.status() == QDataStream::Ok)
return true; return true;
break;
case 0x16: // route
case 0x15: // info header
default:
skipRecord(stream);
}
}
_errorString = "Invalid/corrupted GPI data";
return false;
} }
bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec **codec) bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec **codec)
@ -495,57 +525,33 @@ bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec **codec)
return true; return true;
} }
void GPIParser::readPOIDatabase(QDataStream &stream, QTextCodec *codec, bool GPIParser::readFileHeader(QDataStream &stream, quint32 &ebs)
QVector<Waypoint> &waypoints)
{ {
RecordHeader rh; RecordHeader rh;
QList<TranslatedString> obj; quint32 ds, s7;
quint32 ds; quint16 s10;
quint8 s5, s6, s8, s9;
char magic[6];
readRecordHeader(stream, rh); readRecordHeader(stream, rh);
ds = readTranslatedObjects(stream, codec, obj); stream.readRawData(magic, sizeof(magic));
ds += readSpatialIndex(stream, codec, waypoints); if (memcmp(magic, "GRMREC", sizeof(magic))) {
if (rh.flags & 0x8) { _errorString = "Not a GPI file";
while (ds < rh.size) {
switch(nextHeaderType(stream)) {
case 5: // symbol
case 7: // category
default:
ds += skipRecord(stream);
}
}
}
if (ds != rh.size)
stream.setStatus(QDataStream::ReadCorruptData);
}
bool GPIParser::readEntry(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints)
{
switch (nextHeaderType(stream)) {
case 0x09: // POI database
readPOIDatabase(stream, codec, waypoints);
break;
case 0xffff: // EOF
skipRecord(stream);
return false; return false;
case 0x16: // route
case 0x15: // info header
default:
skipRecord(stream);
} }
stream >> s5 >> s6 >> s7 >> s8 >> s9 >> s10;
stream.skipRawData(s10);
ds = sizeof(magic) + 10 + s10;
if (rh.flags & 8)
ds += readFprsRecord(stream);
return (stream.status() == QDataStream::Ok); ebs = (s8 & 0x4) ? s9 * 8 + 8 : 0;
}
bool GPIParser::readData(QDataStream &stream, QTextCodec *codec, if (stream.status() != QDataStream::Ok || ds != rh.size) {
QVector<Waypoint> &waypoints) _errorString = "Invalid file header";
{ return false;
while (readEntry(stream, codec, waypoints)) } else
; return true;
return (stream.status() == QDataStream::Ok);
} }
bool GPIParser::parse(QFile *file, QList<TrackData> &tracks, bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
@ -557,7 +563,7 @@ bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
QDataStream stream(file); QDataStream stream(file);
QTextCodec *codec = 0; QTextCodec *codec = 0;
quint32 ebs; quint32 ebs;
bool ret; int imgId = 0;
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
@ -568,13 +574,7 @@ bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
CryptDevice dev(stream.device(), 0xf870b5, ebs); CryptDevice dev(stream.device(), 0xf870b5, ebs);
QDataStream cryptStream(&dev); QDataStream cryptStream(&dev);
cryptStream.setByteOrder(QDataStream::LittleEndian); cryptStream.setByteOrder(QDataStream::LittleEndian);
ret = readData(cryptStream, codec, waypoints); return readData(cryptStream, codec, waypoints, file->fileName(), imgId);
} else } else
ret = readData(stream, codec, waypoints); return readData(stream, codec, waypoints, file->fileName(), imgId);
if (!ret) {
_errorString = "Invalid/corrupted GPI data";
return false;
} else
return true;
} }

View File

@ -18,11 +18,7 @@ private:
bool readFileHeader(QDataStream &stream, quint32 &ebs); bool readFileHeader(QDataStream &stream, quint32 &ebs);
bool readGPIHeader(QDataStream &stream, QTextCodec **codec); bool readGPIHeader(QDataStream &stream, QTextCodec **codec);
bool readData(QDataStream &stream, QTextCodec *codec, bool readData(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints); QVector<Waypoint> &waypoints, const QString &fileName, int &imgId);
bool readEntry(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints);
void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints);
QString _errorString; QString _errorString;
}; };