From 37a0eec48ff0575b847b97fba6a930cba6efe969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Thu, 5 Sep 2019 22:31:13 +0200 Subject: [PATCH] Added support for pseudo-NT IMG maps (e.g. TopoHispania) --- src/map/IMG/img.cpp | 13 ++++--------- src/map/IMG/lblfile.cpp | 6 +++--- src/map/IMG/lblfile.h | 7 +++++-- src/map/IMG/netfile.cpp | 2 +- src/map/IMG/netfile.h | 5 +++-- src/map/IMG/rgnfile.cpp | 36 +++++++++++++++++++++-------------- src/map/IMG/rgnfile.h | 14 +++++++++----- src/map/IMG/style.cpp | 2 +- src/map/IMG/subfile.cpp | 27 +++++++------------------- src/map/IMG/subfile.h | 23 ++++++++++++++-------- src/map/IMG/trefile.cpp | 14 +++++++------- src/map/IMG/trefile.h | 3 ++- src/map/IMG/vectortile.cpp | 39 +++++++++++++++++++++++++++++--------- src/map/IMG/vectortile.h | 10 +++++++--- 14 files changed, 116 insertions(+), 85 deletions(-) diff --git a/src/map/IMG/img.cpp b/src/map/IMG/img.cpp index 30623003..c34812e6 100644 --- a/src/map/IMG/img.cpp +++ b/src/map/IMG/img.cpp @@ -9,7 +9,7 @@ #define CHECK(condition) \ if (!(condition)) { \ - _errorString = "Invalid/corrupted IMG file"; \ + _errorString = "Unsupported or invalid IMG file"; \ return; \ } @@ -85,11 +85,6 @@ IMG::IMG(const QString &fileName) && read(type, sizeof(type)) && readValue(size) && readValue(part)); SubFile::Type tt = SubFile::type(type); - if (tt == SubFile::GMP) { - _errorString = "NT maps not supported"; - return; - } - QString fn(QByteArray(name, sizeof(name))); if (SubFile::isTileFile(tt)) { VectorTile *tile; @@ -101,7 +96,7 @@ IMG::IMG(const QString &fileName) tile = *it; SubFile *file = part ? tile->file(tt) - : tile->addFile(this, tt, size); + : tile->addFile(this, tt); CHECK(file); _file.seek(offset + 0x20); @@ -114,7 +109,7 @@ IMG::IMG(const QString &fileName) } else if (tt == SubFile::TYP) { SubFile *typ = 0; if (typFile.isNull()) { - _typ = new SubFile(this, size); + _typ = new SubFile(this); typ = _typ; typFile = fn; } else if (fn == typFile) @@ -166,7 +161,7 @@ void IMG::load() { Q_ASSERT(!_style); - if (_typ && _typ->isValid()) + if (_typ) _style = new Style(_typ); else { QFile typFile(ProgramPaths::typFile()); diff --git a/src/map/IMG/lblfile.cpp b/src/map/IMG/lblfile.cpp index bf15b6fc..a1b6f9d9 100644 --- a/src/map/IMG/lblfile.cpp +++ b/src/map/IMG/lblfile.cpp @@ -56,11 +56,11 @@ bool LBLFile::init() quint16 codepage; quint8 multiplier, poiMultiplier; - if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset) + if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset) && readUInt32(hdl, _size) && readByte(hdl, multiplier) - && readByte(hdl, _encoding) && seek(hdl, 0x57) + && readByte(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57) && readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize) - && readByte(hdl, poiMultiplier) && seek(hdl, 0xAA) + && readByte(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA) && readUInt16(hdl, codepage))) return false; diff --git a/src/map/IMG/lblfile.h b/src/map/IMG/lblfile.h index 2dfbb334..b7a44670 100644 --- a/src/map/IMG/lblfile.h +++ b/src/map/IMG/lblfile.h @@ -9,9 +9,12 @@ class QTextCodec; class LBLFile : public SubFile { public: - LBLFile(IMG *img, quint32 size) - : SubFile(img, size), _codec(0), _offset(0), _size(0), _poiOffset(0), + LBLFile(IMG *img) + : SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {} + LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), + _codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0), + _poiMultiplier(0), _multiplier(0), _encoding(0) {} Label label(Handle &hdl, quint32 offset, bool poi = false); diff --git a/src/map/IMG/netfile.cpp b/src/map/IMG/netfile.cpp index f9023fb3..36c632b3 100644 --- a/src/map/IMG/netfile.cpp +++ b/src/map/IMG/netfile.cpp @@ -5,7 +5,7 @@ bool NETFile::init() Handle hdl; quint8 multiplier; - if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset) + if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset) && readUInt32(hdl, _size) && readByte(hdl, multiplier))) return false; diff --git a/src/map/IMG/netfile.h b/src/map/IMG/netfile.h index e6f6ea74..a7bf8183 100644 --- a/src/map/IMG/netfile.h +++ b/src/map/IMG/netfile.h @@ -6,8 +6,9 @@ class NETFile : public SubFile { public: - NETFile(IMG *img, quint32 size) - : SubFile(img, size), _offset(0), _size(0), _multiplier(0) {} + NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {} + NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), + _offset(0), _size(0), _multiplier(0) {} bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset); diff --git a/src/map/IMG/rgnfile.cpp b/src/map/IMG/rgnfile.cpp index b6dcfa1b..8dfbbf6c 100644 --- a/src/map/IMG/rgnfile.cpp +++ b/src/map/IMG/rgnfile.cpp @@ -85,17 +85,31 @@ bool RGNFile::BitStream::finish() bool RGNFile::init() { Handle hdl; + quint16 hdrLen; - if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset) - && readUInt32(hdl, _size) && readUInt32(hdl, _polygonsOffset) - && readUInt32(hdl, _polygonsSize) && seek(hdl, 0x39) - && readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize) - && seek(hdl, 0x55) && readUInt32(hdl, _pointsOffset) - && readUInt32(hdl, _pointsSize))) + if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen) + && seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset) + && readUInt32(hdl, _size))) return false; - if (_offset + _size > size()) - return false; + if (hdrLen >= 0x5D) { + if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize) + && seek(hdl, _gmpOffset + 0x39) && readUInt32(hdl, _linesOffset) + && readUInt32(hdl, _linesSize) && seek(hdl, _gmpOffset + 0x55) + && readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize))) + return false; + } + if (hdrLen >= 0x7D) { + quint32 dictOffset, dictSize; + if (!(seek(hdl, _gmpOffset + 0x71) && readUInt32(hdl, dictOffset) + && readUInt32(hdl, dictSize))) + return false; + + if (dictSize || dictOffset) { + qWarning("%s: NT compression not supported", qPrintable(fileName())); + return false; + } + } return true; } @@ -404,9 +418,6 @@ void RGNFile::objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl, { Handle rgnHdl, lblHdl, netHdl; - if (!_size && !init()) - return; - QVector seg(segments(rgnHdl, subdiv)); for (int i = 0; i < seg.size(); i++) { switch (seg.at(i).type()) { @@ -436,9 +447,6 @@ void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl, { Handle rgnHdl, lblHdl; - if (!_size && !init()) - return; - if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) { quint32 start = _polygonsOffset + subdiv->polygonsOffset(); quint32 end = subdiv->polygonsEnd() diff --git a/src/map/IMG/rgnfile.h b/src/map/IMG/rgnfile.h index 70942052..c00b53f7 100644 --- a/src/map/IMG/rgnfile.h +++ b/src/map/IMG/rgnfile.h @@ -11,10 +11,15 @@ class NETFile; class RGNFile : public SubFile { public: - RGNFile(IMG *img, quint32 size) - : SubFile(img, size), _offset(0), _size(0), _polygonsOffset(0), - _polygonsSize(), _linesOffset(), _linesSize(), _pointsOffset(), - _pointsSize() {} + RGNFile(IMG *img) + : SubFile(img), _offset(0), _size(0), _polygonsOffset(0), + _polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0), + _pointsSize(0) {} + RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0), + _size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0), + _linesSize(0), _pointsOffset(0), _pointsSize(0) {} + + bool init(); void objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl, NETFile *net, QList *polygons, QList *lines, @@ -73,7 +78,6 @@ private: static bool sign(BitStream &bs, int &val); static int bitSize(quint8 baseSize, bool variableSign, bool extraBit); - bool init(); QVector segments(Handle &hdl, const SubDiv *subdiv) const; bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net, diff --git a/src/map/IMG/style.cpp b/src/map/IMG/style.cpp index c044af94..4720e1a5 100644 --- a/src/map/IMG/style.cpp +++ b/src/map/IMG/style.cpp @@ -942,7 +942,7 @@ Style::Style(SubFile *typ) defaultPolygonStyle(); defaultPointStyle(); - if (typ && typ->isValid()) + if (typ) parseTYPFile(typ); } diff --git a/src/map/IMG/subfile.cpp b/src/map/IMG/subfile.cpp index 8bb88643..82c67dfc 100644 --- a/src/map/IMG/subfile.cpp +++ b/src/map/IMG/subfile.cpp @@ -20,21 +20,13 @@ SubFile::Type SubFile::type(const char str[3]) return Unknown; } -SubFile::SubFile(QFile *file) : _img(0), _file(file), _size(0) +SubFile::SubFile(QFile *file) :_gmpOffset(0), _img(0), _file(file), _blocks(0) { if (!_file->open(QIODevice::ReadOnly)) qWarning("Error opening %s: %s", qPrintable(_file->fileName()), qPrintable(_file->errorString())); } -bool SubFile::isValid() const -{ - return _file - ? _file->isOpen() - : ((quint32)_img->blockSize() * (quint32)_blocks.size() - _size - < (quint32)_img->blockSize()); -} - bool SubFile::seek(Handle &handle, quint32 pos) const { Q_ASSERT(_img || _file); @@ -46,9 +38,9 @@ bool SubFile::seek(Handle &handle, quint32 pos) const int blockNum = pos / blockSize; if (handle.blockNum != blockNum) { - if (blockNum >= _blocks.size()) + if (blockNum >= _blocks->size()) return false; - if (!_img->readBlock(_blocks.at(blockNum), handle.data)) + if (!_img->readBlock(_blocks->at(blockNum), handle.data)) return false; handle.blockNum = blockNum; } @@ -74,11 +66,6 @@ bool SubFile::readByte(Handle &handle, quint8 &val) const } } -quint32 SubFile::size() const -{ - return _file ? (quint32)_file->size() : _size; -} - QString SubFile::fileName() const { return _file ? _file->fileName() : _img->fileName(); @@ -88,15 +75,15 @@ QString SubFile::fileName() const QDebug operator<<(QDebug dbg, const SubFile &file) { bool continuous = true; - for (int i = 1; i < file._blocks.size(); i++) { - if (file._blocks.at(i) != file._blocks.at(i-1) + 1) { + for (int i = 1; i < file._blocks->size(); i++) { + if (file._blocks->at(i) != file._blocks->at(i-1) + 1) { continuous = false; break; } } - dbg.nospace() << "SubFile(" << file._size << ", " << file._blocks.size() - << ", " << continuous << ")"; + dbg.nospace() << "SubFile(" << file._blocks->size() << ", " + << continuous << ")"; return dbg.space(); } #endif // QT_NO_DEBUG diff --git a/src/map/IMG/subfile.h b/src/map/IMG/subfile.h index 5d061f2f..33614857 100644 --- a/src/map/IMG/subfile.h +++ b/src/map/IMG/subfile.h @@ -22,13 +22,14 @@ public: int pos; }; - SubFile(IMG *img, quint32 size) : _img(img), _file(0), _size(size) {} + SubFile(IMG *img) : _gmpOffset(0), _img(img), _file(0), + _blocks(&_blockData) {} + SubFile(SubFile *gmp, quint32 offset) : _gmpOffset(offset), _img(gmp->_img), + _file(0), _blocks(&(gmp->_blockData)) {} SubFile(QFile *file); - void addBlock(quint16 block) {_blocks.append(block);} - bool isValid() const; + void addBlock(quint16 block) {_blocks->append(block);} - quint32 size() const; bool seek(Handle &handle, quint32 pos) const; bool readByte(Handle &handle, quint8 &val) const; @@ -80,20 +81,26 @@ public: return true; } - quint16 offset() const {return _blocks.first();} + quint16 offset() const {return _blocks->first();} QString fileName() const; static Type type(const char str[3]); static bool isTileFile(Type type) - {return (type == TRE || type == LBL || type == RGN || type == NET);} + { + return (type == TRE || type == LBL || type == RGN || type == NET + || type == GMP); + } friend QDebug operator<<(QDebug dbg, const SubFile &file); +protected: + quint32 _gmpOffset; + private: IMG *_img; QFile *_file; - quint32 _size; - QVector _blocks; + QVector *_blocks; + QVector _blockData; }; #ifndef QT_NO_DEBUG diff --git a/src/map/IMG/trefile.cpp b/src/map/IMG/trefile.cpp index a0e66796..40435a1b 100644 --- a/src/map/IMG/trefile.cpp +++ b/src/map/IMG/trefile.cpp @@ -43,28 +43,28 @@ bool TREFile::init() quint8 locked; quint16 hdrLen; - if (!(seek(hdl, 0) && readUInt16(hdl, hdrLen) - && seek(hdl, 0x0D) && readByte(hdl, locked))) + if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen) + && seek(hdl, _gmpOffset + 0x0D) && readByte(hdl, locked))) return false; // Tile bounds qint32 north, east, south, west; - if (!(seek(hdl, 0x15) && readInt24(hdl, north) && readInt24(hdl, east) - && readInt24(hdl, south) && readInt24(hdl, west))) + if (!(seek(hdl, _gmpOffset + 0x15) && readInt24(hdl, north) + && readInt24(hdl, east) && readInt24(hdl, south) && readInt24(hdl, west))) return false; _bounds = RectC(Coordinates(toWGS84(west), toWGS84(north)), Coordinates(toWGS84(east), toWGS84(south))); // Levels & subdivs info quint32 levelsOffset, levelsSize, subdivSize; - if (!(seek(hdl, 0x21) && readUInt32(hdl, levelsOffset) + if (!(seek(hdl, _gmpOffset + 0x21) && readUInt32(hdl, levelsOffset) && readUInt32(hdl, levelsSize) && readUInt32(hdl, _subdivOffset) && readUInt32(hdl, subdivSize))) return false; // TRE7 info if (hdrLen > 0x9A) { - if (!(seek(hdl, 0x7C) && readUInt32(hdl, _extended.offset) + if (!(seek(hdl, _gmpOffset + 0x7C) && readUInt32(hdl, _extended.offset) && readUInt32(hdl, _extended.size) && readUInt16(hdl, _extended.itemSize))) return false; @@ -80,7 +80,7 @@ bool TREFile::init() if (locked) { quint32 key; quint8 unlocked[64]; - if (!seek(hdl, 0xAA) || !readUInt32(hdl, key)) + if (!seek(hdl, _gmpOffset + 0xAA) || !readUInt32(hdl, key)) return false; unlock(unlocked, levels, levelsSize, key); memcpy(levels, unlocked, levelsSize); diff --git a/src/map/IMG/trefile.h b/src/map/IMG/trefile.h index 1cec1161..6251de57 100644 --- a/src/map/IMG/trefile.h +++ b/src/map/IMG/trefile.h @@ -13,7 +13,8 @@ class SubDiv; class TREFile : public SubFile { public: - TREFile(IMG *img, quint32 size) : SubFile(img, size) {} + TREFile(IMG *img) : SubFile(img) {} + TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {} ~TREFile(); bool init(); diff --git a/src/map/IMG/vectortile.cpp b/src/map/IMG/vectortile.cpp index d2146316..3ca25351 100644 --- a/src/map/IMG/vectortile.cpp +++ b/src/map/IMG/vectortile.cpp @@ -11,26 +11,31 @@ SubFile *VectorTile::file(SubFile::Type type) return _lbl; case SubFile::NET: return _net; + case SubFile::GMP: + return _gmp; default: return 0; } } -SubFile *VectorTile::addFile(IMG *img, SubFile::Type type, quint32 size) +SubFile *VectorTile::addFile(IMG *img, SubFile::Type type) { switch (type) { case SubFile::TRE: - _tre = new TREFile(img, size); + _tre = new TREFile(img); return _tre; case SubFile::RGN: - _rgn = new RGNFile(img, size); + _rgn = new RGNFile(img); return _rgn; case SubFile::LBL: - _lbl = new LBLFile(img, size); + _lbl = new LBLFile(img); return _lbl; case SubFile::NET: - _net = new NETFile(img, size); + _net = new NETFile(img); return _net; + case SubFile::GMP: + _gmp = new SubFile(img); + return _gmp; default: return 0; } @@ -38,14 +43,30 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type, quint32 size) bool VectorTile::init() { - if (!(_tre && _tre->isValid() && _tre->init() && _rgn - && _rgn->isValid())) + if (_gmp && !initGMP()) return false; - if (_lbl && !_lbl->isValid()) + + if (!(_tre && _tre->init() && _rgn && _rgn->init())) return false; - if (_net && !_net->isValid()) + + return true; +} + +bool VectorTile::initGMP() +{ + SubFile::Handle hdl; + quint32 tre, rgn, lbl, net; + + if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre) + && _gmp->readUInt32(hdl, rgn) && _gmp->readUInt32(hdl, lbl) + && _gmp->readUInt32(hdl, net))) return false; + _tre = new TREFile(_gmp, tre); + _rgn = new RGNFile(_gmp, rgn); + _lbl = new LBLFile(_gmp, lbl); + _net = new NETFile(_gmp, net); + return true; } diff --git a/src/map/IMG/vectortile.h b/src/map/IMG/vectortile.h index e2ce6172..101d0cc2 100644 --- a/src/map/IMG/vectortile.h +++ b/src/map/IMG/vectortile.h @@ -10,8 +10,9 @@ class VectorTile { public: - VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0) {} - ~VectorTile() {delete _tre; delete _rgn; delete _lbl; delete _net;} + VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {} + ~VectorTile() + {delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp;} bool init(); void clear() {_tre->clear();} @@ -19,7 +20,7 @@ public: const RectC &bounds() const {return _tre->bounds();} SubFile *file(SubFile::Type type); - SubFile *addFile(IMG *img, SubFile::Type type, quint32 size); + SubFile *addFile(IMG *img, SubFile::Type type); void objects(const RectC &rect, int bits, QList *polygons, QList *lines, QList *points) const; @@ -27,10 +28,13 @@ public: friend QDebug operator<<(QDebug dbg, const VectorTile &tile); private: + bool initGMP(); + TREFile *_tre; RGNFile *_rgn; LBLFile *_lbl; NETFile *_net; + SubFile *_gmp; }; #ifndef QT_NO_DEBUG