1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-01-18 19:52:09 +01:00

Improved error handling/reporting.

+ refactoring
This commit is contained in:
Martin Tůma 2021-07-01 22:18:45 +02:00
parent f4d0c7f032
commit 34e3e04e03
2 changed files with 151 additions and 79 deletions

View File

@ -15,11 +15,6 @@
#define MAGIC "CompeGPSRasterImage" #define MAGIC "CompeGPSRasterImage"
#define CHECK(condition) \
if (!(condition)) { \
_errorString = "Invalid/corrupted RMap file"; \
return; \
}
static CalibrationPoint parseCalibrationPoint(const QString &str) static CalibrationPoint parseCalibrationPoint(const QString &str)
{ {
@ -149,6 +144,125 @@ bool RMap::parseIMP(const QByteArray &data)
return true; return true;
} }
bool RMap::readPalette(QDataStream &stream, quint32 paletteSize)
{
quint32 bgr;
if (paletteSize > 256)
return false;
_palette.resize(256);
for (int i = 0; i < (int)paletteSize; i++) {
stream >> bgr;
_palette[i] = Color::bgr2rgb(bgr);
}
return (stream.status() == QDataStream::Ok);
}
bool RMap::readZoomLevel(quint64 offset, const QSize &imageSize)
{
if (!_file.seek(offset))
return false;
QDataStream stream(&_file);
stream.setByteOrder(QDataStream::LittleEndian);
_zooms.append(Zoom());
Zoom &zoom = _zooms.last();
quint32 width, height;
stream >> width >> height;
zoom.size = QSize(width, -(int)height);
stream >> width >> height;
zoom.dim = QSize(width, height);
zoom.scale = QPointF((qreal)zoom.size.width() / (qreal)imageSize.width(),
(qreal)zoom.size.height() / (qreal)imageSize.height());
if (stream.status() != QDataStream::Ok)
return false;
zoom.tiles.resize(zoom.dim.width() * zoom.dim.height());
for (int j = 0; j < zoom.tiles.size(); j++)
stream >> zoom.tiles[j];
return (stream.status() == QDataStream::Ok);
}
bool RMap::readZooms(QDataStream &stream, const QSize &imageSize)
{
qint32 zoomCount;
stream >> zoomCount;
if (!(stream.status() == QDataStream::Ok && zoomCount))
return false;
QVector<quint64> zoomOffsets(zoomCount);
for (int i = 0; i < zoomCount; i++)
stream >> zoomOffsets[i];
if (stream.status() != QDataStream::Ok)
return false;
for (int i = 0; i < zoomOffsets.size(); i++)
if (!readZoomLevel(zoomOffsets.at(i), imageSize))
return false;
return true;
}
QByteArray RMap::readIMP(quint64 IMPOffset)
{
if (!_file.seek(IMPOffset))
return QByteArray();
QDataStream stream(&_file);
stream.setByteOrder(QDataStream::LittleEndian);
quint32 IMPSize, unknown;
stream >> unknown >> IMPSize;
if (stream.status() != QDataStream::Ok)
return QByteArray();
QByteArray IMP;
IMP.resize(IMPSize);
return (stream.readRawData(IMP.data(), IMP.size()) == IMP.size())
? IMP : QByteArray();
}
bool RMap::readHeader(QDataStream &stream, Header &hdr)
{
quint32 subtype, obfuscated;
char magic[sizeof(MAGIC) - 1];
if (stream.readRawData(magic, sizeof(magic)) != sizeof(magic)
|| memcmp(MAGIC, magic, sizeof(magic))) {
_errorString = "Not a raster RMap file";
return false;
}
stream >> hdr.type;
if (hdr.type > 5)
stream >> subtype;
if (hdr.type > 6)
stream >> obfuscated;
else
obfuscated = 0;
stream >> hdr.width >> hdr.height >> hdr.bpp >> hdr.unknown >> hdr.tileWidth
>> hdr.tileHeight >> hdr.IMPOffset >> hdr.paletteSize;
if (stream.status() != QDataStream::Ok) {
_errorString = "Error reading RMap header";
return false;
}
if (hdr.type < 4 || hdr.type > 10) {
_errorString = QString::number(hdr.type) + ": unsupported map type";
return false;
}
if (obfuscated) {
_errorString = "Obfuscated maps not supported";
return false;
}
return true;
}
RMap::RMap(const QString &fileName, QObject *parent) RMap::RMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _file(fileName), _mapRatio(1.0), _zoom(0), : Map(fileName, parent), _file(fileName), _mapRatio(1.0), _zoom(0),
_valid(false) _valid(false)
@ -161,86 +275,27 @@ RMap::RMap(const QString &fileName, QObject *parent)
QDataStream stream(&_file); QDataStream stream(&_file);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
char magic[sizeof(MAGIC) - 1]; Header hdr;
if (stream.readRawData(magic, sizeof(magic)) != sizeof(magic) if (!readHeader(stream, hdr))
|| memcmp(MAGIC, magic, sizeof(magic))) { return;
_errorString = "Not a raster RMap file";
_tileSize = QSize(hdr.tileWidth, hdr.tileHeight);
if (hdr.paletteSize && !readPalette(stream, hdr.paletteSize)) {
_errorString = "Error reading color palette";
return; return;
} }
quint32 unknown, type, subtype, obfuscated, width, height, bpp, tileWidth, if (!readZooms(stream, QSize(hdr.width, -(int)hdr.height))) {
tileHeight, paletteSize; _errorString = "Error reading zoom levels";
quint64 IMPOffset;
stream >> type;
if (type > 5)
stream >> subtype >> obfuscated;
else
obfuscated = 0;
stream >> width >> height >> bpp >> unknown >> tileWidth >> tileHeight
>> IMPOffset >> paletteSize;
CHECK(stream.status() == QDataStream::Ok);
if (!(type == 5 || (type >= 8 && type <= 10))) {
_errorString = QString::number(type) + ": unsupported map type";
return;
}
if (obfuscated) {
_errorString = "Obfuscated maps not supported";
return; return;
} }
QSize imageSize(width, -(int)height); QByteArray IMP(readIMP(hdr.IMPOffset));
_tileSize = QSize(tileWidth, tileHeight); if (IMP.isNull()) {
_errorString = "Error reading IMP data";
if (paletteSize) { return;
quint32 bgr;
CHECK(paletteSize <= 256);
_palette.resize(256);
for (int i = 0; i < (int)paletteSize; i++) {
stream >> bgr;
_palette[i] = Color::bgr2rgb(bgr);
}
} }
qint32 zoomCount;
stream >> zoomCount;
CHECK(stream.status() == QDataStream::Ok && zoomCount);
QVector<quint64> zoomOffsets(zoomCount);
for (int i = 0; i < zoomCount; i++)
stream >> zoomOffsets[i];
CHECK(stream.status() == QDataStream::Ok);
for (int i = 0; i < zoomOffsets.size(); i++) {
_zooms.append(Zoom());
Zoom &zoom = _zooms.last();
CHECK(_file.seek(zoomOffsets.at(i)));
quint32 width, height;
stream >> width >> height;
zoom.size = QSize(width, -(int)height);
stream >> width >> height;
zoom.dim = QSize(width, height);
zoom.scale = QPointF((qreal)zoom.size.width() / (qreal)imageSize.width(),
(qreal)zoom.size.height() / (qreal)imageSize.height());
CHECK(stream.status() == QDataStream::Ok);
zoom.tiles.resize(zoom.dim.width() * zoom.dim.height());
for (int j = 0; j < zoom.tiles.size(); j++)
stream >> zoom.tiles[j];
CHECK(stream.status() == QDataStream::Ok);
}
CHECK(_file.seek(IMPOffset));
quint32 IMPSize;
stream >> unknown >> IMPSize;
CHECK(stream.status() == QDataStream::Ok);
QByteArray IMP(IMPSize + 1, 0);
stream.readRawData(IMP.data(), IMP.size());
_valid = parseIMP(IMP); _valid = parseIMP(IMP);
_file.close(); _file.close();
@ -358,7 +413,7 @@ QPixmap RMap::tile(int x, int y)
if (stream.readRawData(ba.data(), ba.size()) != ba.size()) if (stream.readRawData(ba.data(), ba.size()) != ba.size())
return QPixmap(); return QPixmap();
QImage img(QImage::fromData(ba)); QImage img(QImage::fromData(ba, "JPG"));
return QPixmap::fromImage(img); return QPixmap::fromImage(img);
} else } else
return QPixmap(); return QPixmap();

View File

@ -35,6 +35,18 @@ public:
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
private: private:
struct Header {
quint32 type;
quint32 width;
quint32 height;
quint32 bpp;
quint32 unknown;
quint32 tileWidth;
quint32 tileHeight;
quint32 paletteSize;
quint64 IMPOffset;
};
struct Zoom { struct Zoom {
QSize size; QSize size;
QSize dim; QSize dim;
@ -42,6 +54,11 @@ private:
QVector<quint64> tiles; QVector<quint64> tiles;
}; };
bool readHeader(QDataStream &stream, Header &hdr);
bool readPalette(QDataStream &stream, quint32 paletteSize);
bool readZooms(QDataStream &stream, const QSize &imageSize);
bool readZoomLevel(quint64 offset, const QSize &imageSize);
QByteArray readIMP(quint64 IMPOffset);
bool parseIMP(const QByteArray &data); bool parseIMP(const QByteArray &data);
QPixmap tile(int x, int y); QPixmap tile(int x, int y);