1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 05:34:47 +01:00

Added support for pseudo-NT IMG maps (e.g. TopoHispania)

This commit is contained in:
Martin Tůma 2019-09-05 22:31:13 +02:00
parent fcaacb4b6a
commit 37a0eec48f
14 changed files with 116 additions and 85 deletions

View File

@ -9,7 +9,7 @@
#define CHECK(condition) \ #define CHECK(condition) \
if (!(condition)) { \ if (!(condition)) { \
_errorString = "Invalid/corrupted IMG file"; \ _errorString = "Unsupported or invalid IMG file"; \
return; \ return; \
} }
@ -85,11 +85,6 @@ IMG::IMG(const QString &fileName)
&& read(type, sizeof(type)) && readValue(size) && readValue(part)); && read(type, sizeof(type)) && readValue(size) && readValue(part));
SubFile::Type tt = SubFile::type(type); SubFile::Type tt = SubFile::type(type);
if (tt == SubFile::GMP) {
_errorString = "NT maps not supported";
return;
}
QString fn(QByteArray(name, sizeof(name))); QString fn(QByteArray(name, sizeof(name)));
if (SubFile::isTileFile(tt)) { if (SubFile::isTileFile(tt)) {
VectorTile *tile; VectorTile *tile;
@ -101,7 +96,7 @@ IMG::IMG(const QString &fileName)
tile = *it; tile = *it;
SubFile *file = part ? tile->file(tt) SubFile *file = part ? tile->file(tt)
: tile->addFile(this, tt, size); : tile->addFile(this, tt);
CHECK(file); CHECK(file);
_file.seek(offset + 0x20); _file.seek(offset + 0x20);
@ -114,7 +109,7 @@ IMG::IMG(const QString &fileName)
} else if (tt == SubFile::TYP) { } else if (tt == SubFile::TYP) {
SubFile *typ = 0; SubFile *typ = 0;
if (typFile.isNull()) { if (typFile.isNull()) {
_typ = new SubFile(this, size); _typ = new SubFile(this);
typ = _typ; typ = _typ;
typFile = fn; typFile = fn;
} else if (fn == typFile) } else if (fn == typFile)
@ -166,7 +161,7 @@ void IMG::load()
{ {
Q_ASSERT(!_style); Q_ASSERT(!_style);
if (_typ && _typ->isValid()) if (_typ)
_style = new Style(_typ); _style = new Style(_typ);
else { else {
QFile typFile(ProgramPaths::typFile()); QFile typFile(ProgramPaths::typFile());

View File

@ -56,11 +56,11 @@ bool LBLFile::init()
quint16 codepage; quint16 codepage;
quint8 multiplier, poiMultiplier; quint8 multiplier, poiMultiplier;
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset) if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier) && 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) && readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
&& readByte(hdl, poiMultiplier) && seek(hdl, 0xAA) && readByte(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
&& readUInt16(hdl, codepage))) && readUInt16(hdl, codepage)))
return false; return false;

View File

@ -9,9 +9,12 @@ class QTextCodec;
class LBLFile : public SubFile class LBLFile : public SubFile
{ {
public: public:
LBLFile(IMG *img, quint32 size) LBLFile(IMG *img)
: SubFile(img, size), _codec(0), _offset(0), _size(0), _poiOffset(0), : SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(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); Label label(Handle &hdl, quint32 offset, bool poi = false);

View File

@ -5,7 +5,7 @@ bool NETFile::init()
Handle hdl; Handle hdl;
quint8 multiplier; quint8 multiplier;
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset) if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier))) && readUInt32(hdl, _size) && readByte(hdl, multiplier)))
return false; return false;

View File

@ -6,8 +6,9 @@
class NETFile : public SubFile class NETFile : public SubFile
{ {
public: public:
NETFile(IMG *img, quint32 size) NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {}
: SubFile(img, size), _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); bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);

View File

@ -85,17 +85,31 @@ bool RGNFile::BitStream::finish()
bool RGNFile::init() bool RGNFile::init()
{ {
Handle hdl; Handle hdl;
quint16 hdrLen;
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset) if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& readUInt32(hdl, _size) && readUInt32(hdl, _polygonsOffset) && seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _polygonsSize) && seek(hdl, 0x39) && readUInt32(hdl, _size)))
&& readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize)
&& seek(hdl, 0x55) && readUInt32(hdl, _pointsOffset)
&& readUInt32(hdl, _pointsSize)))
return false; return false;
if (_offset + _size > size()) if (hdrLen >= 0x5D) {
return false; 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; return true;
} }
@ -404,9 +418,6 @@ void RGNFile::objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
{ {
Handle rgnHdl, lblHdl, netHdl; Handle rgnHdl, lblHdl, netHdl;
if (!_size && !init())
return;
QVector<RGNFile::Segment> seg(segments(rgnHdl, subdiv)); QVector<RGNFile::Segment> seg(segments(rgnHdl, subdiv));
for (int i = 0; i < seg.size(); i++) { for (int i = 0; i < seg.size(); i++) {
switch (seg.at(i).type()) { switch (seg.at(i).type()) {
@ -436,9 +447,6 @@ void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
{ {
Handle rgnHdl, lblHdl; Handle rgnHdl, lblHdl;
if (!_size && !init())
return;
if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) { if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) {
quint32 start = _polygonsOffset + subdiv->polygonsOffset(); quint32 start = _polygonsOffset + subdiv->polygonsOffset();
quint32 end = subdiv->polygonsEnd() quint32 end = subdiv->polygonsEnd()

View File

@ -11,10 +11,15 @@ class NETFile;
class RGNFile : public SubFile class RGNFile : public SubFile
{ {
public: public:
RGNFile(IMG *img, quint32 size) RGNFile(IMG *img)
: SubFile(img, size), _offset(0), _size(0), _polygonsOffset(0), : SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
_polygonsSize(), _linesOffset(), _linesSize(), _pointsOffset(), _polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
_pointsSize() {} _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, void objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
@ -73,7 +78,6 @@ private:
static bool sign(BitStream &bs, int &val); static bool sign(BitStream &bs, int &val);
static int bitSize(quint8 baseSize, bool variableSign, bool extraBit); static int bitSize(quint8 baseSize, bool variableSign, bool extraBit);
bool init();
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const; QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const;
bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net, const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,

View File

@ -942,7 +942,7 @@ Style::Style(SubFile *typ)
defaultPolygonStyle(); defaultPolygonStyle();
defaultPointStyle(); defaultPointStyle();
if (typ && typ->isValid()) if (typ)
parseTYPFile(typ); parseTYPFile(typ);
} }

View File

@ -20,21 +20,13 @@ SubFile::Type SubFile::type(const char str[3])
return Unknown; 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)) if (!_file->open(QIODevice::ReadOnly))
qWarning("Error opening %s: %s", qPrintable(_file->fileName()), qWarning("Error opening %s: %s", qPrintable(_file->fileName()),
qPrintable(_file->errorString())); 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 bool SubFile::seek(Handle &handle, quint32 pos) const
{ {
Q_ASSERT(_img || _file); Q_ASSERT(_img || _file);
@ -46,9 +38,9 @@ bool SubFile::seek(Handle &handle, quint32 pos) const
int blockNum = pos / blockSize; int blockNum = pos / blockSize;
if (handle.blockNum != blockNum) { if (handle.blockNum != blockNum) {
if (blockNum >= _blocks.size()) if (blockNum >= _blocks->size())
return false; return false;
if (!_img->readBlock(_blocks.at(blockNum), handle.data)) if (!_img->readBlock(_blocks->at(blockNum), handle.data))
return false; return false;
handle.blockNum = blockNum; 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 QString SubFile::fileName() const
{ {
return _file ? _file->fileName() : _img->fileName(); return _file ? _file->fileName() : _img->fileName();
@ -88,15 +75,15 @@ QString SubFile::fileName() const
QDebug operator<<(QDebug dbg, const SubFile &file) QDebug operator<<(QDebug dbg, const SubFile &file)
{ {
bool continuous = true; bool continuous = true;
for (int i = 1; i < file._blocks.size(); i++) { for (int i = 1; i < file._blocks->size(); i++) {
if (file._blocks.at(i) != file._blocks.at(i-1) + 1) { if (file._blocks->at(i) != file._blocks->at(i-1) + 1) {
continuous = false; continuous = false;
break; break;
} }
} }
dbg.nospace() << "SubFile(" << file._size << ", " << file._blocks.size() dbg.nospace() << "SubFile(" << file._blocks->size() << ", "
<< ", " << continuous << ")"; << continuous << ")";
return dbg.space(); return dbg.space();
} }
#endif // QT_NO_DEBUG #endif // QT_NO_DEBUG

View File

@ -22,13 +22,14 @@ public:
int pos; 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); SubFile(QFile *file);
void addBlock(quint16 block) {_blocks.append(block);} void addBlock(quint16 block) {_blocks->append(block);}
bool isValid() const;
quint32 size() const;
bool seek(Handle &handle, quint32 pos) const; bool seek(Handle &handle, quint32 pos) const;
bool readByte(Handle &handle, quint8 &val) const; bool readByte(Handle &handle, quint8 &val) const;
@ -80,20 +81,26 @@ public:
return true; return true;
} }
quint16 offset() const {return _blocks.first();} quint16 offset() const {return _blocks->first();}
QString fileName() const; QString fileName() const;
static Type type(const char str[3]); static Type type(const char str[3]);
static bool isTileFile(Type type) 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); friend QDebug operator<<(QDebug dbg, const SubFile &file);
protected:
quint32 _gmpOffset;
private: private:
IMG *_img; IMG *_img;
QFile *_file; QFile *_file;
quint32 _size; QVector<quint16> *_blocks;
QVector<quint16> _blocks; QVector<quint16> _blockData;
}; };
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG

View File

@ -43,28 +43,28 @@ bool TREFile::init()
quint8 locked; quint8 locked;
quint16 hdrLen; quint16 hdrLen;
if (!(seek(hdl, 0) && readUInt16(hdl, hdrLen) if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& seek(hdl, 0x0D) && readByte(hdl, locked))) && seek(hdl, _gmpOffset + 0x0D) && readByte(hdl, locked)))
return false; return false;
// Tile bounds // Tile bounds
qint32 north, east, south, west; qint32 north, east, south, west;
if (!(seek(hdl, 0x15) && readInt24(hdl, north) && readInt24(hdl, east) if (!(seek(hdl, _gmpOffset + 0x15) && readInt24(hdl, north)
&& readInt24(hdl, south) && readInt24(hdl, west))) && readInt24(hdl, east) && readInt24(hdl, south) && readInt24(hdl, west)))
return false; return false;
_bounds = RectC(Coordinates(toWGS84(west), toWGS84(north)), _bounds = RectC(Coordinates(toWGS84(west), toWGS84(north)),
Coordinates(toWGS84(east), toWGS84(south))); Coordinates(toWGS84(east), toWGS84(south)));
// Levels & subdivs info // Levels & subdivs info
quint32 levelsOffset, levelsSize, subdivSize; 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, levelsSize) && readUInt32(hdl, _subdivOffset)
&& readUInt32(hdl, subdivSize))) && readUInt32(hdl, subdivSize)))
return false; return false;
// TRE7 info // TRE7 info
if (hdrLen > 0x9A) { if (hdrLen > 0x9A) {
if (!(seek(hdl, 0x7C) && readUInt32(hdl, _extended.offset) if (!(seek(hdl, _gmpOffset + 0x7C) && readUInt32(hdl, _extended.offset)
&& readUInt32(hdl, _extended.size) && readUInt32(hdl, _extended.size)
&& readUInt16(hdl, _extended.itemSize))) && readUInt16(hdl, _extended.itemSize)))
return false; return false;
@ -80,7 +80,7 @@ bool TREFile::init()
if (locked) { if (locked) {
quint32 key; quint32 key;
quint8 unlocked[64]; quint8 unlocked[64];
if (!seek(hdl, 0xAA) || !readUInt32(hdl, key)) if (!seek(hdl, _gmpOffset + 0xAA) || !readUInt32(hdl, key))
return false; return false;
unlock(unlocked, levels, levelsSize, key); unlock(unlocked, levels, levelsSize, key);
memcpy(levels, unlocked, levelsSize); memcpy(levels, unlocked, levelsSize);

View File

@ -13,7 +13,8 @@ class SubDiv;
class TREFile : public SubFile class TREFile : public SubFile
{ {
public: public:
TREFile(IMG *img, quint32 size) : SubFile(img, size) {} TREFile(IMG *img) : SubFile(img) {}
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
~TREFile(); ~TREFile();
bool init(); bool init();

View File

@ -11,26 +11,31 @@ SubFile *VectorTile::file(SubFile::Type type)
return _lbl; return _lbl;
case SubFile::NET: case SubFile::NET:
return _net; return _net;
case SubFile::GMP:
return _gmp;
default: default:
return 0; return 0;
} }
} }
SubFile *VectorTile::addFile(IMG *img, SubFile::Type type, quint32 size) SubFile *VectorTile::addFile(IMG *img, SubFile::Type type)
{ {
switch (type) { switch (type) {
case SubFile::TRE: case SubFile::TRE:
_tre = new TREFile(img, size); _tre = new TREFile(img);
return _tre; return _tre;
case SubFile::RGN: case SubFile::RGN:
_rgn = new RGNFile(img, size); _rgn = new RGNFile(img);
return _rgn; return _rgn;
case SubFile::LBL: case SubFile::LBL:
_lbl = new LBLFile(img, size); _lbl = new LBLFile(img);
return _lbl; return _lbl;
case SubFile::NET: case SubFile::NET:
_net = new NETFile(img, size); _net = new NETFile(img);
return _net; return _net;
case SubFile::GMP:
_gmp = new SubFile(img);
return _gmp;
default: default:
return 0; return 0;
} }
@ -38,14 +43,30 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type, quint32 size)
bool VectorTile::init() bool VectorTile::init()
{ {
if (!(_tre && _tre->isValid() && _tre->init() && _rgn if (_gmp && !initGMP())
&& _rgn->isValid()))
return false; return false;
if (_lbl && !_lbl->isValid())
if (!(_tre && _tre->init() && _rgn && _rgn->init()))
return false; 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; return false;
_tre = new TREFile(_gmp, tre);
_rgn = new RGNFile(_gmp, rgn);
_lbl = new LBLFile(_gmp, lbl);
_net = new NETFile(_gmp, net);
return true; return true;
} }

View File

@ -10,8 +10,9 @@
class VectorTile { class VectorTile {
public: public:
VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0) {} VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {}
~VectorTile() {delete _tre; delete _rgn; delete _lbl; delete _net;} ~VectorTile()
{delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp;}
bool init(); bool init();
void clear() {_tre->clear();} void clear() {_tre->clear();}
@ -19,7 +20,7 @@ public:
const RectC &bounds() const {return _tre->bounds();} const RectC &bounds() const {return _tre->bounds();}
SubFile *file(SubFile::Type type); 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<IMG::Poly> *polygons, void objects(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *lines, QList<IMG::Point> *points) const; QList<IMG::Poly> *lines, QList<IMG::Point> *points) const;
@ -27,10 +28,13 @@ public:
friend QDebug operator<<(QDebug dbg, const VectorTile &tile); friend QDebug operator<<(QDebug dbg, const VectorTile &tile);
private: private:
bool initGMP();
TREFile *_tre; TREFile *_tre;
RGNFile *_rgn; RGNFile *_rgn;
LBLFile *_lbl; LBLFile *_lbl;
NETFile *_net; NETFile *_net;
SubFile *_gmp;
}; };
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG