mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-28 05:34:47 +01:00
Do not duplicate temporary images + improved error handling
This commit is contained in:
parent
9e63e3f47e
commit
3632ed8816
@ -6,6 +6,7 @@
|
||||
#include <QApplication>
|
||||
#include <QBuffer>
|
||||
#include <QImageReader>
|
||||
#include <QCryptographicHash>
|
||||
#include <QTemporaryDir>
|
||||
#include "gpiparser.h"
|
||||
|
||||
@ -109,7 +110,6 @@ qint64 CryptDevice::readData(char *data, qint64 maxSize)
|
||||
return ts;
|
||||
}
|
||||
|
||||
static int cnt = 0;
|
||||
|
||||
static const QTemporaryDir &tempDir()
|
||||
{
|
||||
@ -125,7 +125,12 @@ static inline double toWGS(qint32 v)
|
||||
static quint16 nextHeaderType(QDataStream &stream)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -146,18 +151,6 @@ static quint32 skipRecord(QDataStream &stream)
|
||||
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)
|
||||
{
|
||||
quint16 len;
|
||||
@ -180,7 +173,7 @@ static quint32 readTranslatedObjects(QDataStream &stream, QTextCodec *codec,
|
||||
|
||||
stream >> size;
|
||||
ret = size + 4;
|
||||
while (size > 0) {
|
||||
while (stream.status() == QDataStream::Ok && size > 0) {
|
||||
QString str;
|
||||
stream.readRawData(lang, sizeof(lang));
|
||||
size -= readString(stream, codec, str) + 2;
|
||||
@ -193,6 +186,67 @@ static quint32 readTranslatedObjects(QDataStream &stream, QTextCodec *codec,
|
||||
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,
|
||||
Waypoint &waypoint)
|
||||
{
|
||||
@ -276,7 +330,8 @@ static quint32 readContact(QDataStream &stream, QTextCodec *codec,
|
||||
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;
|
||||
quint8 rs, s1;
|
||||
@ -292,7 +347,9 @@ static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint)
|
||||
QBuffer buf(&ba);
|
||||
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()))));
|
||||
imgFile.open(QIODevice::WriteOnly);
|
||||
imgFile.write(ba);
|
||||
@ -307,7 +364,7 @@ static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint)
|
||||
}
|
||||
|
||||
static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints)
|
||||
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs;
|
||||
@ -326,7 +383,7 @@ static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
|
||||
if (!obj.isEmpty())
|
||||
waypoints.last().setName(obj.first().str());
|
||||
|
||||
while (ds < rh.size) {
|
||||
while (stream.status() == QDataStream::Ok && ds < rh.size) {
|
||||
switch(nextHeaderType(stream)) {
|
||||
case 10:
|
||||
ds += readDescription(stream, codec, waypoints.last());
|
||||
@ -335,7 +392,7 @@ static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
|
||||
ds += readContact(stream, codec, waypoints.last());
|
||||
break;
|
||||
case 13:
|
||||
ds += readImageInfo(stream, waypoints.last());
|
||||
ds += readImageInfo(stream, waypoints.last(), fileName, imgId);
|
||||
break;
|
||||
case 14:
|
||||
ds += readNotes(stream, codec, waypoints.last());
|
||||
@ -352,7 +409,7 @@ static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
|
||||
}
|
||||
|
||||
static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints)
|
||||
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint32 ds, s5;
|
||||
@ -365,13 +422,14 @@ static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
|
||||
stream.skipRawData(s6);
|
||||
ds = 22 + s6;
|
||||
if (rh.flags & 0x8) {
|
||||
while (ds < rh.size) {
|
||||
while (stream.status() == QDataStream::Ok && ds < rh.size) {
|
||||
switch(nextHeaderType(stream)) {
|
||||
case 2:
|
||||
ds += readPOI(stream, codec, waypoints);
|
||||
ds += readPOI(stream, codec, waypoints, fileName, imgId);
|
||||
break;
|
||||
case 8:
|
||||
ds += readSpatialIndex(stream, codec, waypoints);
|
||||
ds += readSpatialIndex(stream, codec, waypoints, fileName,
|
||||
imgId);
|
||||
break;
|
||||
default:
|
||||
ds += skipRecord(stream);
|
||||
@ -385,82 +443,54 @@ static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
bool GPIParser::readFileHeader(QDataStream &stream, quint32 &ebs)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint32 ds, s7;
|
||||
quint16 s10;
|
||||
quint8 s5, s6, s8, s9;
|
||||
char magic[6];
|
||||
quint32 ds;
|
||||
|
||||
readRecordHeader(stream, rh);
|
||||
stream.readRawData(magic, sizeof(magic));
|
||||
if (memcmp(magic, "GRMREC", sizeof(magic))) {
|
||||
_errorString = "Not a GPI file";
|
||||
return false;
|
||||
ds = readTranslatedObjects(stream, codec, obj);
|
||||
ds += readSpatialIndex(stream, codec, waypoints, fileName, imgId);
|
||||
if (rh.flags & 0x8) {
|
||||
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) {
|
||||
_errorString = "Invalid file header";
|
||||
return false;
|
||||
} else
|
||||
bool GPIParser::readData(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
@ -495,57 +525,33 @@ bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec **codec)
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPIParser::readPOIDatabase(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints)
|
||||
bool GPIParser::readFileHeader(QDataStream &stream, quint32 &ebs)
|
||||
{
|
||||
RecordHeader rh;
|
||||
QList<TranslatedString> obj;
|
||||
quint32 ds;
|
||||
quint32 ds, s7;
|
||||
quint16 s10;
|
||||
quint8 s5, s6, s8, s9;
|
||||
char magic[6];
|
||||
|
||||
readRecordHeader(stream, rh);
|
||||
ds = readTranslatedObjects(stream, codec, obj);
|
||||
ds += readSpatialIndex(stream, codec, waypoints);
|
||||
if (rh.flags & 0x8) {
|
||||
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);
|
||||
stream.readRawData(magic, sizeof(magic));
|
||||
if (memcmp(magic, "GRMREC", sizeof(magic))) {
|
||||
_errorString = "Not a GPI file";
|
||||
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,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
while (readEntry(stream, codec, waypoints))
|
||||
;
|
||||
|
||||
return (stream.status() == QDataStream::Ok);
|
||||
if (stream.status() != QDataStream::Ok || ds != rh.size) {
|
||||
_errorString = "Invalid file header";
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
@ -557,7 +563,7 @@ bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QDataStream stream(file);
|
||||
QTextCodec *codec = 0;
|
||||
quint32 ebs;
|
||||
bool ret;
|
||||
int imgId = 0;
|
||||
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
|
||||
@ -568,13 +574,7 @@ bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
CryptDevice dev(stream.device(), 0xf870b5, ebs);
|
||||
QDataStream cryptStream(&dev);
|
||||
cryptStream.setByteOrder(QDataStream::LittleEndian);
|
||||
ret = readData(cryptStream, codec, waypoints);
|
||||
return readData(cryptStream, codec, waypoints, file->fileName(), imgId);
|
||||
} else
|
||||
ret = readData(stream, codec, waypoints);
|
||||
|
||||
if (!ret) {
|
||||
_errorString = "Invalid/corrupted GPI data";
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
return readData(stream, codec, waypoints, file->fileName(), imgId);
|
||||
}
|
||||
|
@ -18,11 +18,7 @@ private:
|
||||
bool readFileHeader(QDataStream &stream, quint32 &ebs);
|
||||
bool readGPIHeader(QDataStream &stream, QTextCodec **codec);
|
||||
bool readData(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints);
|
||||
bool readEntry(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints);
|
||||
void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints);
|
||||
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId);
|
||||
|
||||
QString _errorString;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user