diff --git a/gpxsee.pro b/gpxsee.pro index dfa7679d..ec60447f 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -95,6 +95,7 @@ HEADERS += src/common/config.h \ src/map/IMG/gmap.h \ src/map/IMG/huffmanstream.h \ src/map/IMG/huffmantable.h \ + src/map/IMG/nodfile.h \ src/map/IMG/mapdata.h \ src/map/IMG/rastertile.h \ src/map/IMG/textpathitem.h \ @@ -257,6 +258,7 @@ SOURCES += src/main.cpp \ src/map/IMG/gmap.cpp \ src/map/IMG/huffmanstream.cpp \ src/map/IMG/huffmantable.cpp \ + src/map/IMG/nodfile.cpp \ src/map/IMG/mapdata.cpp \ src/map/IMG/rastertile.cpp \ src/map/IMG/textpathitem.cpp \ diff --git a/src/map/IMG/bitstream.cpp b/src/map/IMG/bitstream.cpp index 771e32ff..57302d18 100644 --- a/src/map/IMG/bitstream.cpp +++ b/src/map/IMG/bitstream.cpp @@ -41,8 +41,19 @@ bool BitStream1::flush() return true; } +bool BitStream4::flush() +{ + if (_length && !_file.seek(_hdl, _hdl.pos() + _length)) + return false; -bool BitStream4::read(int bits, quint32 &val) + _length = 0; + _used = 32; + _unused = 0; + + return true; +} + +bool BitStream4F::read(int bits, quint32 &val) { if (bits <= 32 - (int)(_used + _unused)) { val = bits ? (_data << _used) >> (32 - bits) : 0; @@ -50,6 +61,8 @@ bool BitStream4::read(int bits, quint32 &val) return true; } + if (_unused) + return false; quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0; quint32 bytes = qMin(_length, 4U); @@ -66,14 +79,123 @@ bool BitStream4::read(int bits, quint32 &val) return true; } -bool BitStream4::flush() +BitStream4R::BitStream4R(const SubFile &file, SubFile::Handle &hdl, + quint32 length) : BitStream4(file, hdl, length) { - if (_length && !_file.seek(_hdl, _hdl.pos() + _length)) + _file.seek(_hdl, _hdl.pos() - 4); +} + +bool BitStream4R::readBytes(int bytes, quint32 &val) +{ + quint32 bits = _used % 8; + quint32 b; + + if (bits) { + if (!read(8 - bits, b)) + return false; + Q_ASSERT(!b); + } + + return read(bytes * 8, val); +} + +bool BitStream4R::readVUInt32(quint32 &val) +{ + quint32 b; + quint8 bytes, shift; + + if (!readBytes(1, b)) return false; - _length = 0; - _used = 32; - _unused = 0; + if ((b & 1) == 0) { + if ((b & 2) == 0) { + bytes = ((b >> 2) & 1) ^ 3; + shift = 5; + } else { + shift = 6; + bytes = 1; + } + } else { + shift = 7; + bytes = 0; + } + + val = b >> (8 - shift); + + if (bytes) { + if (!readBytes(bytes, b)) + return false; + val = val | (b << shift); + } return true; } + +bool BitStream4R::readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits) +{ + quint32 b, eb; + + if (!readBytes(1, b)) + return false; + + if (!(b & 1)) { + val1 = b >> 3 & 0x1f; + val2 = b >> 1 & 3; + val2Bits = 2; + } else { + eb = b & 2; + val2 = b >> 2 & 0x3f; + val2Bits = eb * 2 + 6; + if (!readBytes((eb >> 1 | 2) - 1, b)) + return false; + if (eb) { + val2 = val2 | (b & 0xf) << 6; + b = b >> 4 & 0xfff; + } + val1 = b; + } + + return true; +} + +bool BitStream4R::skip(quint32 bytes) +{ + if (bytes * 8 > bitsAvailable()) + return false; + + quint32 ab = (32 - (_used + _unused))/8; + if (bytes <= ab) + _used += bytes * 8; + else { + quint32 seek = ((bytes - ab)/4)*4; + quint32 read = (bytes - ab)%4; + if (seek && !_file.seek(_hdl, _hdl.pos() - seek)) + return false; + _length -= seek; + if (read) { + quint32 rb = qMin(_length, 4U); + if (!_file.readUInt32(_hdl, _data)) + return false; + if (!_file.seek(_hdl, _hdl.pos() - 8)) + return false; + _length -= rb; + _unused = (4 - rb) * 8; + _used = read * 8; + } else + _used = 32; + } + + return true; +} + +void BitStream4R::resize(quint32 length) +{ + quint32 ab = (32 - _used)/8; + + if (ab < length) + _length = length - ab; + else { + _length = 0; + _used += length * 8; + } +} diff --git a/src/map/IMG/bitstream.h b/src/map/IMG/bitstream.h index edec780c..0e159222 100644 --- a/src/map/IMG/bitstream.h +++ b/src/map/IMG/bitstream.h @@ -10,7 +10,7 @@ public: bool read(int bits, quint32 &val); bool flush(); - quint32 bitsAvailable() const {return _length * 8 + _remaining;} + quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;} private: const SubFile &_file; @@ -25,15 +25,64 @@ public: : _file(file), _hdl(hdl), _length(length), _used(32), _unused(0), _data(0) {} - bool read(int bits, quint32 &val); bool flush(); - quint32 bitsAvailable() const {return _length * 8 + (32 - _used) - _unused;} + quint64 bitsAvailable() const + {return (quint64)_length * 8 + (32 - _used) - _unused;} -private: +protected: const SubFile &_file; SubFile::Handle &_hdl; quint32 _length, _used, _unused; quint32 _data; }; +class BitStream4F : public BitStream4 { +public: + BitStream4F(const SubFile &file, SubFile::Handle &hdl, quint32 length) + : BitStream4(file, hdl, length) {} + + bool read(int bits, quint32 &val); +}; + +class BitStream4R : public BitStream4 { +public: + BitStream4R(const SubFile &file, SubFile::Handle &hdl, quint32 length); + + template bool read(int bits, T &val); + bool readBytes(int bytes, quint32 &val); + bool readVUInt32(quint32 &val); + bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits); + + bool skip(quint32 bytes); + void resize(quint32 length); +}; + +template +bool BitStream4R::read(int bits, T &val) +{ + if (bits <= 32 - (int)(_used + _unused)) { + val = bits ? (_data << _used) >> (32 - bits) : 0; + _used += bits; + return true; + } + + if (_unused) + return false; + quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0; + quint32 bytes = qMin(_length, 4U); + + if (!_file.readUInt32(_hdl, _data)) + return false; + if (!_file.seek(_hdl, _hdl.pos() - 8)) + return false; + + _length -= bytes; + _used -= 32 - bits; + _unused = (4 - bytes) * 8; + + val = _data >> (32 - _used) | old; + + return true; +} + #endif // BITSTREAM_H diff --git a/src/map/IMG/huffmanstream.cpp b/src/map/IMG/huffmanstream.cpp index 2482664c..8680496a 100644 --- a/src/map/IMG/huffmanstream.cpp +++ b/src/map/IMG/huffmanstream.cpp @@ -1,74 +1,30 @@ #include "huffmanstream.h" - -HuffmanStream::HuffmanStream(const SubFile &file, SubFile::Handle &hdl, - quint32 length, const HuffmanTable &table, bool line) - : BitStream4(file, hdl, length), _table(table), _symbolDataSize(0), - _symbolData(0) +bool HuffmanStreamF::init(bool line) { if (line) { if (!(sign(_lonSign) && sign(_latSign))) - return; + return false; } else { _lonSign = 0; _latSign = 0; } quint32 eb; - if (!read(1, eb)) - return; + if (!_bs.read(1, eb)) + return false; if (eb) { - qWarning("Extended polygon/lines not supported"); - flush(); - } -} - -bool HuffmanStream::sign(int &val) -{ - quint32 bit; - val = 0; - - if (!read(1, bit)) + qWarning() << "Extended lines/polygons not supported"; return false; - if (bit) { - if (!read(1, bit)) - return false; - val = bit ? -1 : 1; } return true; } -bool HuffmanStream::readDelta(int sign, qint32 &symbol) +bool HuffmanStreamR::init() { - quint8 size; - quint32 next; - quint8 nextSize = qMin((quint32)(32 - _symbolDataSize), bitsAvailable()); - - if (!read(nextSize, next)) + if (!(sign(_lonSign) && sign(_latSign))) return false; - _symbolData = (_symbolData << nextSize) | next; - _symbolDataSize += nextSize; - - symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size); - - if (size <= _symbolDataSize) - _symbolDataSize -= size; - else - return false; - - if (symbol && !sign) { - if (!_symbolDataSize) - return false; - else { - sign = ((1U << (_symbolDataSize - 1)) & _symbolData) ? -1 : 1; - _symbolDataSize--; - } - } - symbol = sign * symbol; - return true; } - - diff --git a/src/map/IMG/huffmanstream.h b/src/map/IMG/huffmanstream.h index ad44443f..51149931 100644 --- a/src/map/IMG/huffmanstream.h +++ b/src/map/IMG/huffmanstream.h @@ -4,10 +4,12 @@ #include "bitstream.h" #include "huffmantable.h" -class HuffmanStream : public BitStream4 { +template +class HuffmanStream { public: - HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length, - const HuffmanTable &table, bool line); + HuffmanStream(BitStream &bitstream, const HuffmanTable &table) + : _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0), + _lonSign(0), _latSign(0) {} bool readNext(qint32 &lonDelta, qint32 &latDelta) { @@ -17,19 +19,87 @@ public: return (lonDelta || latDelta); } - bool readOffset(qint32 &lonDelta, qint32 &latDelta) - {return (readDelta(1, lonDelta) && readDelta(1, latDelta));} bool atEnd() const - {return _symbolDataSize + bitsAvailable() < _table.maxSymbolSize();} + {return _symbolDataSize + _bs.bitsAvailable() < _table.maxSymbolSize();} + bool flush() {return _bs.flush();} -private: +protected: bool sign(int &val); bool readDelta(int sign, qint32 &delta); + BitStream &_bs; const HuffmanTable &_table; quint32 _symbolDataSize; quint32 _symbolData; int _lonSign, _latSign; }; +template +bool HuffmanStream::sign(int &val) +{ + quint32 bit; + val = 0; + + if (!_bs.read(1, bit)) + return false; + if (bit) { + if (!_bs.read(1, bit)) + return false; + val = bit ? -1 : 1; + } + + return true; +} + +template +bool HuffmanStream::readDelta(int sign, qint32 &symbol) +{ + quint8 size; + quint32 next; + quint8 nextSize = qMin((quint64)(32 - _symbolDataSize), _bs.bitsAvailable()); + + if (!_bs.read(nextSize, next)) + return false; + + _symbolData = (_symbolData << nextSize) | next; + _symbolDataSize += nextSize; + + symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size); + + if (size <= _symbolDataSize) + _symbolDataSize -= size; + else + return false; + + if (symbol && !sign) { + if (!_symbolDataSize) + return false; + else { + sign = ((1U << (_symbolDataSize - 1)) & _symbolData) ? -1 : 1; + _symbolDataSize--; + } + } + symbol = sign * symbol; + + return true; +} + +class HuffmanStreamF : public HuffmanStream { +public: + HuffmanStreamF(BitStream4F &bitstream, const HuffmanTable &table) + : HuffmanStream(bitstream, table) {} + + bool init(bool line); + bool readOffset(qint32 &lonDelta, qint32 &latDelta) + {return (readDelta(1, lonDelta) && readDelta(1, latDelta));} +}; + +class HuffmanStreamR : public HuffmanStream { +public: + HuffmanStreamR(BitStream4R &bitstream, const HuffmanTable &table) + : HuffmanStream(bitstream, table) {} + + bool init(); +}; + #endif // HUFFMANSTREAM_H diff --git a/src/map/IMG/huffmantable.cpp b/src/map/IMG/huffmantable.cpp index cdf3c519..ad35f116 100644 --- a/src/map/IMG/huffmantable.cpp +++ b/src/map/IMG/huffmantable.cpp @@ -42,6 +42,8 @@ bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl, _s10 = _s14 + _s1c * _s1d; _s18 = _s10 + (_s1 << _s0); + _id = id; + return true; } diff --git a/src/map/IMG/huffmantable.h b/src/map/IMG/huffmantable.h index 53bf89f5..335dda02 100644 --- a/src/map/IMG/huffmantable.h +++ b/src/map/IMG/huffmantable.h @@ -13,6 +13,8 @@ public: quint8 maxSymbolSize() const {return _s2;} quint32 symbol(quint32 data, quint8 &size) const; + quint8 id() const {return _id;} + private: bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset, quint32 size, quint8 id); @@ -22,6 +24,8 @@ private: quint8 *_s10, *_s14, *_s18; quint8 _s1c, _s1d, _s1e, _s1f, _s20; quint16 _s22; + + quint8 _id; }; #endif // HUFFMANTABLE_H diff --git a/src/map/IMG/img.cpp b/src/map/IMG/img.cpp index 13c66d2f..7fd52ca3 100644 --- a/src/map/IMG/img.cpp +++ b/src/map/IMG/img.cpp @@ -59,7 +59,7 @@ IMG::IMG(const QString &fileName) : _file(fileName) QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2))); _name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed(); - _blockSize = 1 << (e1 + e2); + _blockBits = e1 + e2; // Read the FAT table quint8 flag; @@ -132,7 +132,6 @@ IMG::IMG(const QString &fileName) : _file(fileName) } // Create tile tree - int minMapZoom = 24; for (TileMap::const_iterator it = tileMap.constBegin(); it != tileMap.constEnd(); ++it) { @@ -159,14 +158,19 @@ IMG::IMG(const QString &fileName) : _file(fileName) minMapZoom = tile->zooms().min(); } - for (TileMap::const_iterator it = tileMap.constBegin(); - it != tileMap.constEnd(); ++it) { - VectorTile *tile = it.value(); + // Detect and mark basemap + TileTree::Iterator it; + for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) { + VectorTile *tile = _tileTree.GetAt(it); if (tile->zooms().min() > minMapZoom) _baseMap = true; if (tile->zooms().min() == minMapZoom) tile->markAsBasemap(); } + // Allow some extra zoom out on maps without basemaps, but not too much as + // this would kill the rendering performance + if (!_baseMap) + _zooms.setMin(_zooms.min() - 2); if (!_tileTree.Count()) _errorString = "No usable map tile found"; @@ -197,9 +201,9 @@ template bool IMG::readValue(T &val) bool IMG::readBlock(int blockNum, char *data) { - if (!_file.seek((qint64)blockNum * (qint64)_blockSize)) + if (!_file.seek((quint64)blockNum << _blockBits)) return false; - if (read(data, _blockSize) < _blockSize) + if (read(data, 1U<<_blockBits) < 1U<<_blockBits) return false; return true; diff --git a/src/map/IMG/img.h b/src/map/IMG/img.h index 7173a447..4718c8c3 100644 --- a/src/map/IMG/img.h +++ b/src/map/IMG/img.h @@ -14,14 +14,14 @@ public: private: friend class SubFile; - int blockSize() const {return _blockSize;} + unsigned blockBits() const {return _blockBits;} bool readBlock(int blockNum, char *data); qint64 read(char *data, qint64 maxSize); template bool readValue(T &val); QFile _file; quint8 _key; - int _blockSize; + unsigned _blockBits; }; #endif // IMG_H diff --git a/src/map/IMG/mapdata.cpp b/src/map/IMG/mapdata.cpp index 724f78ed..ce0a48fb 100644 --- a/src/map/IMG/mapdata.cpp +++ b/src/map/IMG/mapdata.cpp @@ -54,7 +54,7 @@ inline bool pointCb(VectorTile *tile, void *context) } -MapData::MapData() : _typ(0), _style(0), _zooms(15, 28), _baseMap(false), +MapData::MapData() : _typ(0), _style(0), _zooms(24, 28), _baseMap(false), _valid(false) { _polyCache.setMaxCost(CACHED_SUBDIVS_COUNT); diff --git a/src/map/IMG/netfile.cpp b/src/map/IMG/netfile.cpp index 7b5324f8..552e033b 100644 --- a/src/map/IMG/netfile.cpp +++ b/src/map/IMG/netfile.cpp @@ -1,5 +1,89 @@ +#include "bitstream.h" +#include "huffmanstream.h" +#include "subdiv.h" +#include "nodfile.h" #include "netfile.h" + +bool adjCnts(BitStream4R &bs, QVector &cnts, quint16 &mask) +{ + quint32 val, cnt, bits; + if (!bs.read(4, val)) + return false; + + cnt = ((val >> 2) & 3) + 2; + bits = ((val * 2) & 6) + 4; + mask = 1<<(3 + ((val * 2) & 6)); + if (cnt == 5) { + if (!bs.read(8, cnt)) + return false; + Q_ASSERT(cnt > 4); + } + + if (cnt < 2) + return false; + cnts.resize(cnt - 1); + for (int i = 0; i < cnts.size(); i++) + if (!bs.read(bits, cnts[i])) + return false; + + return true; +} + +bool skipNodes(BitStream4R &bs, const QVector &cnts, quint16 mask) +{ + for (int i = 0; i < cnts.size(); i++) { + if (cnts.at(i) & mask) { + quint32 v1, v2, v2b; + if (!bs.readVuint32SM(v1, v2, v2b)) + return false; + if (!bs.skip(v1)) + return false; + } + } + + return true; +} + +bool seekToLevel(BitStream4R &bs, quint8 level) +{ + quint32 v1, v2, v2b; + + for (quint8 i = 1; i < level; ) { + if (!bs.readVuint32SM(v1, v2, v2b)) + return false; + if (!bs.skip(v1)) + return false; + + Q_ASSERT(!(v2 & 2)); + if (v2 & 2) + return false; + if (v2 & 1) + i++; + }; + + return true; +} + +bool seekToLine(BitStream4R &bs, quint8 line) +{ + quint32 v1, v2, v2b; + + for (quint8 i = 0; i < line; i++) { + if (!bs.readVuint32SM(v1, v2, v2b)) + return false; + if (!bs.skip(v1)) + return false; + + Q_ASSERT(!(v2 & 2)); + if (v2 & 2) + return false; + } + + return true; +} + + bool NETFile::init(Handle &hdl) { quint8 multiplier; @@ -10,11 +94,121 @@ bool NETFile::init(Handle &hdl) && readUInt32(hdl, _size) && readUInt8(hdl, multiplier))) return false; + if (hdrLen >= 0x47) { + quint32 info; + if (!(seek(hdl, _gmpOffset + 0x37) && readUInt32(hdl, info))) + return false; + _tableId = ((info >> 2) & 0xF); + + if (!(seek(hdl, _gmpOffset + 0x43) && readUInt32(hdl, _linksOffset) + && readUInt32(hdl, _linksSize) && readUInt8(hdl, _linksShift))) + return false; + } + _multiplier = 1< *lines) +{ + if (!_multiplier && !init(hdl)) + return false; + + // TODO + if (!subdiv->level()) + return false; + + NODFile::LinkInfo linkInfo; + if (!nod->linkInfo(nodHdl, blockInfo, linkId, linkInfo)) + return false; + + quint32 linkOffset = _linksOffset + (linkInfo.linkOffset << _linksShift); + Q_ASSERT(linkOffset <= _linksOffset + _linksSize); + + quint8 s68 = (linkInfo.flags >> 0x12) & 1; + quint8 s69 = (linkInfo.flags >> 0x11) & 1; + quint8 s6a = (linkInfo.flags >> 0x13) & 1; + + if (s6a == 1) { + QVector ca; + quint16 mask; + + if (!seek(hdl, linkOffset)) + return false; + + BitStream4R bs(*this, hdl, linkOffset - _linksOffset); + quint32 size; + + if (!bs.readVUInt32(size)) + return false; + + if (s69 == 0) { + if (!adjCnts(bs, ca, mask)) + return false; + } + if (s68 == 1) { + quint32 v1, v2, v2b; + if (!bs.readVuint32SM(v1, v2, v2b)) + return false; + Q_ASSERT(v1); + if (!bs.skip(v1)) + return false; + } + if (!skipNodes(bs, ca, mask)) + return false; + if (!seekToLevel(bs, subdiv->level())) + return false; + if (!seekToLine(bs, lineId)) + return false; + + quint32 v1, v2, v2b; + if (!bs.readVuint32SM(v1, v2, v2b)) + return false; + bs.resize(v1); + + quint32 lon, lat; + if (!(bs.read(0x12 - v2b, lon) && bs.read(16, lat))) + return false; + if (2 < v2b) + lon |= (v2 >> 2) << (0x12U - v2b); + + QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon, + 32-subdiv->bits()), LS(subdiv->lat(), 8) + LS((qint16)lat, + 32-subdiv->bits())); + Coordinates c(toWGS32(pos.x()), toWGS32(pos.y())); + + IMG::Poly poly; + if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type)) + return false; + poly.boundingRect = RectC(c, c); + poly.points.append(QPointF(c.lon(), c.lat())); + + Q_ASSERT(_tableId == table.id()); + HuffmanStreamR stream(bs, table); + if (!stream.init()) + return false; + qint32 lonDelta, latDelta; + + while (stream.readNext(lonDelta, latDelta)) { + pos.rx() += LS(lonDelta, 32-subdiv->bits()); + if (pos.rx() < 0 && subdiv->lon() >= 0) + pos.rx() = 0x7fffffff; + pos.ry() += LS(latDelta, 32-subdiv->bits()); + + Coordinates c(toWGS32(pos.x()), toWGS32(pos.y())); + poly.points.append(QPointF(c.lon(), c.lat())); + poly.boundingRect = poly.boundingRect.united(c); + } + + lines->append(poly); + } + + return true; +} + bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) { if (!_multiplier && !init(hdl)) diff --git a/src/map/IMG/netfile.h b/src/map/IMG/netfile.h index bc0779ff..554a3032 100644 --- a/src/map/IMG/netfile.h +++ b/src/map/IMG/netfile.h @@ -1,25 +1,37 @@ #ifndef NETFILE_H #define NETFILE_H +#include "img.h" #include "subfile.h" +#include "nodfile.h" + +class NODFile; +class LBLFile; +class SubDiv; +class HuffmanTable; class NETFile : public SubFile { public: - NETFile(IMG *img) - : SubFile(img), _offset(0), _size(0), _multiplier(0) {} - NETFile(const QString &path) - : SubFile(path), _offset(0), _size(0), _multiplier(0) {} - NETFile(SubFile *gmp, quint32 offset) - : SubFile(gmp, offset), _offset(0), _size(0), _multiplier(0) {} + NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0), + _linksSize(0), _multiplier(0), _linksShift(0) {} + NETFile(const QString &path) : SubFile(path), _offset(0), _size(0), + _linksOffset(0), _linksSize(0), _multiplier(0), _linksShift(0) {} + NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), + _offset(0), _size(0), _linksOffset(0), _linksSize(0), _multiplier(0), + _linksShift(0) {} bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset); + bool link(const SubDiv *subdiv, Handle &hdl, NODFile *nod, Handle &nodHdl, + const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId, + const HuffmanTable &table, QList *lines); private: bool init(Handle &hdl); - quint32 _offset, _size; - quint8 _multiplier; + quint32 _offset, _size, _linksOffset, _linksSize; + quint8 _multiplier, _linksShift; + quint8 _tableId; }; #endif // NETFILE_H diff --git a/src/map/IMG/nodfile.cpp b/src/map/IMG/nodfile.cpp new file mode 100644 index 00000000..1f3134fb --- /dev/null +++ b/src/map/IMG/nodfile.cpp @@ -0,0 +1,155 @@ +#include "bitstream.h" +#include "nodfile.h" + +bool NODFile::init(Handle &hdl) +{ + quint16 hdrLen; + + if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen))) + return false; + + if (hdrLen >= 0x7b) { + if (!(seek(hdl, _gmpOffset + 0x21) && readUInt8(hdl, _blockShift) + && readUInt8(hdl, _nodeShift))) + return false; + if (!(seek(hdl, _gmpOffset + 0x67) && readUInt32(hdl, _blockOffset) + && readUInt32(hdl, _blockSize) && readUInt16(hdl, _blockRecordSize) + && readUInt32(hdl, _indexOffset) && readUInt32(hdl, _indexSize) + && readUInt16(hdl, _indexRecordSize) && readUInt32(hdl, _indexFlags))) + return false; + } + + return true; +} + +quint32 NODFile::indexIdSize(Handle &hdl) +{ + if (!_indexRecordSize && !init(hdl)) + return 0; + + quint32 indexCount = _indexSize / _indexRecordSize; + if (indexCount <= 0x100) + return 1; + else if (indexCount <= 0x1000) + return 2; + else if (indexCount <= 0x1000000) + return 3; + else + return 0; +} + +bool NODFile::blockInfo(Handle &hdl, quint32 blockIndexId, + BlockInfo &blockInfo) const +{ + quint32 blockOffset; + quint32 offset = _indexRecordSize * blockIndexId + _indexOffset; + quint32 offsetSize = (_indexFlags & 3) + 1; + + + Q_ASSERT(offset <= _indexOffset + _indexSize); + if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset))) + return false; + + blockInfo.offset = (blockOffset << _blockShift) + _blockOffset; + + if (!(seek(hdl, blockInfo.offset) && readUInt16(hdl, blockInfo.h0) + && readUInt32(hdl, blockInfo.h2) && readUInt32(hdl, blockInfo.h6) + && readUInt32(hdl, blockInfo.ha) && readUInt16(hdl, blockInfo.he) + && readUInt8(hdl, blockInfo.h10) && readUInt8(hdl, blockInfo.h11) + && readUInt8(hdl, blockInfo.h12))) + return false; + + return true; +} + +bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId, + LinkInfo &linkInfo) const +{ + Q_ASSERT(linkId < blockInfo.h10); + + quint32 infoOffset = ((blockInfo.he * linkId) >> 3) + 0x13 + + ((blockInfo.h0 >> 0xb) & 1) + blockInfo.offset; + quint32 s1 = ((blockInfo.h0 >> 2) & 0x1f) + 8; + quint32 s2 = (blockInfo.h0 >> 7) & 0xf; + quint32 skip = (blockInfo.he * linkId) & 7; + + Q_ASSERT(infoOffset <= _blockOffset + _blockSize); + if (!seek(hdl, infoOffset)) + return false; + + quint32 unused, flags; + BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset); + if (!(bs.read(skip, unused) && bs.read(0xc, flags))) + return false; + + linkInfo.flags = ((flags << 8) & 0xf0000) | (flags & 0xff); + + if (!(flags << 8 & 0x10000)) { + if (!bs.read(s1, linkInfo.linkOffset)) + return false; + } else { + if (!bs.read(s1 - s2, linkInfo.linkOffset)) + return false; + linkInfo.linkOffset += blockInfo.ha; + } + +/* + if (!bs.read(s2, linkInfo.nodeOffset)) + return false; + linkInfo.nodeOffset = (_blockOffset << _blockShift) - linkInfo.nodeOffset + >> _nodeShift; +*/ + + return true; +} + +bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId, + quint32 &type) const +{ + quint32 offset = ((blockInfo.h10 * blockInfo.he + 7) >> 3) + 0x13 + + blockInfo.offset + ((blockInfo.h0 >> 0xb) & 1) + (quint32)blockInfo.h11 + * 3; + quint32 low = 0; + quint32 high = blockInfo.h12 - 1; + quint32 pos; + quint16 val; + + if (high > 1) { + do { + pos = (low + high) / 2; + + if (!seek(hdl, offset + _blockRecordSize * pos)) + return false; + if (!readUInt16(hdl, val)) + return false; + + quint32 tmp = pos; + if ((val >> 8) <= linkId) { + low = pos; + tmp = high; + } + high = tmp; + } while (low + 1 < high); + } + + if (!seek(hdl, offset + _blockRecordSize * low)) + return false; + if (!readUInt16(hdl, val)) + return false; + + type = val & 0x3f; + + if ((low < high) && (pos != high)) { + if (!seek(hdl, offset + _blockRecordSize * high)) + return false; + if (!readUInt16(hdl, val)) + return false; + if ((val >> 8) <= linkId) { + type = (val & 0x3f); + } + } + + type *= 256; + + return true; +} diff --git a/src/map/IMG/nodfile.h b/src/map/IMG/nodfile.h new file mode 100644 index 00000000..2812d4ac --- /dev/null +++ b/src/map/IMG/nodfile.h @@ -0,0 +1,55 @@ +#ifndef NODFILE_H +#define NODFILE_H + +#include "img.h" +#include "subfile.h" + +class NODFile : public SubFile +{ +public: + struct BlockInfo { + quint32 offset; + quint16 h0; + quint32 h2; + quint32 h6; + quint32 ha; + quint16 he; + quint8 h10; // links count + quint8 h11; + quint8 h12; + }; + + struct LinkInfo { + quint32 linkOffset; + //quint32 nodeOffset; + quint32 flags; + }; + + NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0), + _indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0), + _blockRecordSize(0), _blockShift(0), _nodeShift(0) {} + NODFile(const QString &path) : SubFile(path), _indexOffset(0), _indexSize(0), + _indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0), + _blockRecordSize(0), _blockShift(0), _nodeShift(0) {} + NODFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), + _indexOffset(0), _indexSize(0),_indexFlags(0), _blockOffset(0), + _blockSize(0), _indexRecordSize(0), _blockRecordSize(0), _blockShift(0), + _nodeShift(0) {} + + quint32 indexIdSize(Handle &hdl); + bool blockInfo(Handle &hdl, quint32 blockIndexId, + BlockInfo &blockInfo) const; + bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId, + LinkInfo &linkInfo) const; + bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId, + quint32 &type) const; + +private: + bool init(Handle &hdl); + + quint32 _indexOffset, _indexSize, _indexFlags, _blockOffset, _blockSize; + quint16 _indexRecordSize, _blockRecordSize; + quint8 _blockShift, _nodeShift; +}; + +#endif // NETFILE_H diff --git a/src/map/IMG/rgnfile.cpp b/src/map/IMG/rgnfile.cpp index 86c550bf..abd831ed 100644 --- a/src/map/IMG/rgnfile.cpp +++ b/src/map/IMG/rgnfile.cpp @@ -5,9 +5,12 @@ #include "huffmanstream.h" #include "lblfile.h" #include "netfile.h" +#include "nodfile.h" #include "rgnfile.h" +#define MASK(bits) ((2U << ((bits) - 1U)) - 1U) + static quint64 pointId(const QPoint &pos, quint32 type, quint32 labelPtr) { quint64 id; @@ -52,8 +55,7 @@ bool RGNFile::skipClassFields(Handle &hdl) const return seek(hdl, hdl.pos() + rs); } -bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3], - SegmentType type) const +bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3]) const { quint32 bitfield = 0xFFFFFFFF; @@ -61,29 +63,40 @@ bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3], if (!readVBitfield32(hdl, bitfield)) return false; - for (int i = 0; i < 29; i++) { + for (int i = 0, j = 0; i < 29; i++) { if ((flags[0] >> i) & 1) { if (bitfield & 1) { - quint32 m = flags[(i >> 4) + 1] >> ((i * 2) & 0x1e) & 3; - switch (i) { - case 5: - if (m == 1 && type == Point) { - quint16 u16; - if (!readUInt16(hdl, u16)) - return false; - } - break; - default: - break; - } + quint32 m = flags[(j >> 4) + 1] >> ((j * 2) & 0x1e) & 3; + + quint32 skip = 0; + if (m == 3) { + if (!readVUInt32(hdl, skip)) + return false; + } else + skip = m + 1; + if (!seek(hdl, hdl.pos() + skip)) + return false; } bitfield >>= 1; + j++; } } return true; } +bool RGNFile::skipGblFields(Handle &hdl, quint32 flags) const +{ + int cnt = 0; + + do { + cnt = cnt + (flags & 3); + flags = flags >> 2; + } while (flags != 0); + + return seek(hdl, hdl.pos() + cnt); +} + void RGNFile::clearFlags() { memset(_polygonsFlags, 0, sizeof(_polygonsFlags)); @@ -102,14 +115,17 @@ bool RGNFile::init(Handle &hdl) if (hdrLen >= 0x68) { if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize) - && seek(hdl, _gmpOffset + 0x2D) && readUInt32(hdl, _polygonsFlags[0]) - && readUInt32(hdl, _polygonsFlags[1]) && readUInt32(hdl, _polygonsFlags[2]) + && seek(hdl, _gmpOffset + 0x29) && readUInt32(hdl, _polygonGblFlags) + && readUInt32(hdl, _polygonsFlags[0]) && readUInt32(hdl, _polygonsFlags[1]) + && readUInt32(hdl, _polygonsFlags[2]) && readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize) - && seek(hdl, _gmpOffset + 0x49) && readUInt32(hdl, _linesFlags[0]) - && readUInt32(hdl, _linesFlags[1]) && readUInt32(hdl, _linesFlags[2]) + && seek(hdl, _gmpOffset + 0x45) && readUInt32(hdl, _linesGblFlags) + && readUInt32(hdl, _linesFlags[0]) && readUInt32(hdl, _linesFlags[1]) + && readUInt32(hdl, _linesFlags[2]) && readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize) - && seek(hdl, _gmpOffset + 0x65) && readUInt32(hdl, _pointsFlags[0]) - && readUInt32(hdl, _pointsFlags[1]) && readUInt32(hdl, _pointsFlags[2]))) + && seek(hdl, _gmpOffset + 0x61) && readUInt32(hdl, _pointsGblFlags) + && readUInt32(hdl, _pointsFlags[0]) && readUInt32(hdl, _pointsFlags[1]) + && readUInt32(hdl, _pointsFlags[2]))) return false; } @@ -230,6 +246,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, && readInt16(hdl, lon) && readInt16(hdl, lat) && readVUInt32(hdl, len))) return false; + Q_ASSERT(hdl.pos() + len <= segment.end()); poly.type = 0x10000 | (quint16(type)<<8) | (subtype & 0x1F); labelPtr = 0; @@ -239,8 +256,10 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, LS(subdiv->lat(), 8) + LS(lat, (32-subdiv->bits()))); qint32 lonDelta, latDelta; - HuffmanStream stream(*this, hdl, len, _huffmanTable, - segmentType == Line); + BitStream4F bs(*this, hdl, len); + HuffmanStreamF stream(bs, _huffmanTable); + if (!stream.init(segmentType == Line)) + return false; if (shift) { if (!stream.readOffset(lonDelta, latDelta)) @@ -298,7 +317,11 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, if (subtype & 0x80 && !skipClassFields(hdl)) return false; if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line - ? _linesFlags : _polygonsFlags, segmentType)) + ? _linesFlags : _polygonsFlags)) + return false; + quint32 gblFlags = (segmentType == Line) + ? _linesGblFlags : _polygonGblFlags; + if (gblFlags && !skipGblFields(hdl, gblFlags)) return false; if (lbl && (labelPtr & 0x3FFFFF)) @@ -317,6 +340,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv, const SubDiv::Segment &segment = (segmentType == IndexedPoint) ? subdiv->idxPoints() : subdiv->points(); + if (!segment.isValid()) return true; if (!seek(hdl, segment.offset())) @@ -379,7 +403,9 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl, return false; if (subtype & 0x80 && !skipClassFields(hdl)) return false; - if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, Point)) + if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags)) + return false; + if (_pointsGblFlags && !skipGblFields(hdl, _pointsGblFlags)) return false; QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()), @@ -403,6 +429,86 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl, return true; } +bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net, + Handle &netHdl, NODFile *nod, Handle &nodHdl, QList *lines) const +{ + quint32 size, blockIndexIdSize, blockIndexId; + quint8 flags; + const SubDiv::Segment &segment = subdiv->roadReferences(); + + if (!segment.isValid()) + return true; + if (!seek(hdl, segment.offset())) + return false; + + if (!net || !nod) + return false; + if (!(blockIndexIdSize = nod->indexIdSize(nodHdl))) + return false; + + while (hdl.pos() < (int)segment.end()) { + if (!readVUInt32(hdl, size)) + return false; + + int pos = hdl.pos(); + + if (!(readUInt8(hdl, flags) && readVUInt32(hdl, blockIndexIdSize, + blockIndexId))) + return false; + + quint8 bits[3]; + for (int i = 0; i < 3; i++) + bits[i] = 0x4000a08 >> (((flags >> (2*i) & 3) << 3) ^ 0x10); + quint8 byteSize = ((bits[0] + bits[1] + bits[2]) + 7) >> 3; + + quint32 counts; + if (!readVUInt32(hdl, byteSize, counts)) + return false; + + quint16 b8 = bits[0] ? (MASK(bits[0]) & counts) + 1 : 0; + quint16 b10 = bits[1] ? (MASK(bits[1]) & (counts >> bits[0])) + 1 : 0; + quint16 b16 = bits[2] ? (MASK(bits[2]) & (counts >> (bits[0] + bits[1]))) + + 1 : 0; + + NODFile::BlockInfo blockInfo; + if (!nod->blockInfo(nodHdl, blockIndexId, blockInfo)) + return false; + + quint8 linkId, lineId; + for (int i = 0; i < b8 + b10 + b16; i++) { + if (!b8 || b8 <= i) { + quint16 v16; + if (!readUInt16(hdl, v16)) + return false; + + if (!b16 || b8 + b16 <= i) { + int shift = ((i - (b8 + b16)) * 10) % 8; + linkId = (quint8)(v16 >> shift); + lineId = (((v16 >> shift) >> 8) & 3) + 1; + + if (shift < 6 && i < b8 + b10 + b16 - 1) + seek(hdl, hdl.pos() - 1); + } else { + linkId = (quint8)v16; + lineId = v16 >> 8; + Q_ASSERT(lineId > 4); + } + } else { + if (!readUInt8(hdl, linkId)) + return false; + lineId = 0; + } + + net->link(subdiv, netHdl, nod, nodHdl, blockInfo, linkId, lineId, + _huffmanTable, lines); + } + + Q_ASSERT(pos + (int)size == hdl.pos()); + } + + return true; +} + QMap RGNFile::segments(Handle &hdl, SubDiv *subdiv) const { diff --git a/src/map/IMG/rgnfile.h b/src/map/IMG/rgnfile.h index b432147e..9e900c1f 100644 --- a/src/map/IMG/rgnfile.h +++ b/src/map/IMG/rgnfile.h @@ -8,6 +8,7 @@ class LBLFile; class NETFile; +class NODFile; class RGNFile : public SubFile { @@ -46,6 +47,8 @@ public: QList *polys) const; bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl, Handle &lblHdl, QList *points) const; + bool links(Handle &hdl, const SubDiv *subdiv, NETFile *net, Handle &netHdl, + NODFile *nod, Handle &nodHdl, QList *lines) const; bool subdivInit(Handle &hdl, SubDiv *subdiv) const; @@ -54,8 +57,9 @@ private: const; void clearFlags(); bool skipClassFields(Handle &hdl) const; - bool skipLclFields(Handle &hdl, const quint32 flags[3], SegmentType type) + bool skipLclFields(Handle &hdl, const quint32 flags[3]) const; + bool skipGblFields(Handle &hdl, quint32 flags) const; quint32 _offset; quint32 _size; @@ -69,6 +73,9 @@ private: quint32 _pointsOffset; quint32 _pointsSize; quint32 _pointsFlags[3]; + quint32 _polygonGblFlags; + quint32 _linesGblFlags; + quint32 _pointsGblFlags; HuffmanTable _huffmanTable; diff --git a/src/map/IMG/subdiv.h b/src/map/IMG/subdiv.h index 5896d176..d03e4a10 100644 --- a/src/map/IMG/subdiv.h +++ b/src/map/IMG/subdiv.h @@ -21,8 +21,9 @@ public: quint32 _offset, _end; }; - SubDiv(quint32 offset, qint32 lon, qint32 lat, int bits, quint8 objects) - : _lon(lon), _lat(lat), _bits(bits), _init(false) + SubDiv(quint32 offset, qint32 lon, qint32 lat, quint8 level, quint8 bits, + quint8 objects) : _lon(lon), _lat(lat), _level(level), _bits(bits), + _init(false) { _tre.objects = objects; _tre.offset = offset; @@ -78,6 +79,7 @@ public: qint32 lon() const {return _lon;} qint32 lat() const {return _lat;} quint8 bits() const {return _bits;} + quint8 level() const {return _level;} // Valid only after initialization Segment points() const @@ -94,6 +96,8 @@ public: {return Segment(_rgn.extLinesOffset, _rgn.extLinesEnd);} Segment extPolygons() const {return Segment(_rgn.extPolygonsOffset, _rgn.extPolygonsEnd);} + Segment roadReferences() const + {return Segment(_rgn.roadReferencesOffset, _rgn.roadReferencesEnd);} // Valid only until initialization quint8 objects() const {return _tre.objects;} @@ -142,6 +146,7 @@ private: }; qint32 _lon, _lat; + quint8 _level; quint8 _bits; bool _init; union { diff --git a/src/map/IMG/subfile.cpp b/src/map/IMG/subfile.cpp index 42a075de..108f9ac0 100644 --- a/src/map/IMG/subfile.cpp +++ b/src/map/IMG/subfile.cpp @@ -3,26 +3,28 @@ #include "subfile.h" +#define mod2n(x, m) ((x) & ((m) - 1)); + bool SubFile::seek(Handle &handle, quint32 pos) const { if (handle._file) { - int blockNum = pos / BLOCK_SIZE; + int blockNum = pos >> BLOCK_BITS; if (handle._blockNum != blockNum) { - if (!handle._file->seek((qint64)blockNum * BLOCK_SIZE)) + if (!handle._file->seek((quint64)blockNum << BLOCK_BITS)) return false; - if (handle._file->read(handle._data.data(), BLOCK_SIZE) < 0) + if (handle._file->read(handle._data.data(), (1<blockSize(); - int blockNum = pos / blockSize; + quint32 blockBits = _img->blockBits(); + int blockNum = pos >> blockBits; if (handle._blockNum != blockNum) { if (blockNum >= _blocks->size()) @@ -32,7 +34,7 @@ bool SubFile::seek(Handle &handle, quint32 pos) const handle._blockNum = blockNum; } - handle._blockPos = pos % blockSize; + handle._blockPos = mod2n(pos, 1U<_path) { _file = new QFile(*(subFile->_path)); _file->open(QIODevice::ReadOnly); - _data.resize(BLOCK_SIZE); + _data.resize(1U<_img->blockSize()); + _data.resize(1U<_img->blockBits()); } ~Handle() {delete _file;} @@ -132,6 +132,7 @@ public: } bool readVUInt32(Handle &hdl, quint32 &val) const; + bool readVUInt32(Handle &hdl, quint32 bytes, quint32 &val) const; bool readVBitfield32(Handle &hdl, quint32 &bitfield) const; QString fileName() const {return _path ? *_path : _img->fileName();} @@ -142,7 +143,7 @@ protected: private: bool readByte(Handle &handle, quint8 &val) const { - int blockSize = _img ? _img->blockSize() : BLOCK_SIZE; + int blockSize = _img ? 1U<<_img->blockBits() : 1U<= blockSize) diff --git a/src/map/IMG/trefile.cpp b/src/map/IMG/trefile.cpp index f258f5f4..551aa320 100644 --- a/src/map/IMG/trefile.cpp +++ b/src/map/IMG/trefile.cpp @@ -70,14 +70,16 @@ bool TREFile::init() return false; if (hdrLen > 0x9A) { - // TRE7 info + // TRE7 info + flags if (!(seek(hdl, _gmpOffset + 0x7C) && readUInt32(hdl, _extended.offset) && readUInt32(hdl, _extended.size) - && readUInt16(hdl, _extended.itemSize))) - return false; - // flags - if (!(seek(hdl, _gmpOffset + 0x86) && readUInt32(hdl, _flags))) + && readUInt16(hdl, _extended.itemSize) && readUInt32(hdl, _flags))) return false; + } else { + _extended.offset = 0; + _extended.size = 0; + _extended.itemSize = 0; + _flags = 0; } // Tile levels @@ -126,9 +128,10 @@ bool TREFile::load(int idx) QList sl; SubDiv *s = 0; SubDivTree *tree = new SubDivTree(); + const MapLevel &level = _levels.at(idx); - _subdivs.insert(_levels.at(idx).bits, tree); + _subdivs.insert(level.bits, tree); quint32 skip = 0; for (int i = 0; i < idx; i++) @@ -137,7 +140,7 @@ bool TREFile::load(int idx) if (!seek(hdl, _subdivOffset + skip * 16)) return false; - for (int j = 0; j < _levels.at(idx).subdivs; j++) { + for (int j = 0; j < level.subdivs; j++) { quint32 oo; qint32 lon, lat, width, height; quint16 nextLevel; @@ -156,10 +159,10 @@ bool TREFile::load(int idx) s->setEnd(offset); width &= 0x7FFF; - width = LS(width, 24 - _levels.at(idx).bits); - height = LS(height, 24 - _levels.at(idx).bits); + width = LS(width, 24 - level.bits); + height = LS(height, 24 - level.bits); - s = new SubDiv(offset, lon, lat, _levels.at(idx).bits, objects); + s = new SubDiv(offset, lon, lat, level.level, level.bits, objects); sl.append(s); double min[2], max[2]; @@ -184,30 +187,40 @@ bool TREFile::load(int idx) // Objects with extended types (TRE7) - if (_extended.size && _extended.itemSize >= 12) { - /* Some maps skip entries for the inherited levels, some don't. Our - decision is based on the difference between the extended subdivs - count and the total subdivs count. */ + if (_extended.size && _extended.itemSize) { quint32 totalSubdivs = 0; for (int i = 0; i < _levels.size(); i++) totalSubdivs += _levels.at(i).subdivs; quint32 extendedSubdivs = _extended.size / _extended.itemSize; quint32 diff = totalSubdivs - extendedSubdivs + 1; - - quint32 polygons, lines, points; if (!seek(hdl, _extended.offset + (skip - diff) * _extended.itemSize)) goto error; + quint32 polygons = 0, lines = 0, points = 0; for (int i = 0; i < sl.size(); i++) { - if (!(readUInt32(hdl, polygons) && readUInt32(hdl, lines) - && readUInt32(hdl, points))) - goto error; + quint32 rb = 0; + + if (_flags & 1) { + if (!readUInt32(hdl, polygons)) + goto error; + rb += 4; + } + if (_flags & 2) { + if (!readUInt32(hdl, lines)) + goto error; + rb += 4; + } + if (_flags & 4) { + if (!readUInt32(hdl, points)) + goto error; + rb += 4; + } sl.at(i)->setExtOffsets(polygons, lines, points); if (i) sl.at(i-1)->setExtEnds(polygons, lines, points); - if (!seek(hdl, hdl.pos() + _extended.itemSize - 12)) + if (!seek(hdl, hdl.pos() + _extended.itemSize - rb)) goto error; } diff --git a/src/map/IMG/vectortile.cpp b/src/map/IMG/vectortile.cpp index a8f948a7..b127c89d 100644 --- a/src/map/IMG/vectortile.cpp +++ b/src/map/IMG/vectortile.cpp @@ -29,6 +29,8 @@ SubFile *VectorTile::file(SubFile::Type type) return _lbl; case SubFile::NET: return _net; + case SubFile::NOD: + return _nod; case SubFile::GMP: return _gmp; default: @@ -51,6 +53,9 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type) case SubFile::NET: _net = new NETFile(img); return _net; + case SubFile::NOD: + _nod = new NODFile(img); + return _nod; case SubFile::GMP: _gmp = new SubFile(img); return _gmp; @@ -74,6 +79,9 @@ SubFile *VectorTile::addFile(const QString &path, SubFile::Type type) case SubFile::NET: _net = new NETFile(path); return _net; + case SubFile::NOD: + _nod = new NODFile(path); + return _nod; case SubFile::GMP: _gmp = new SubFile(path); return _gmp; @@ -96,17 +104,18 @@ bool VectorTile::init() bool VectorTile::initGMP() { SubFile::Handle hdl(_gmp); - quint32 tre, rgn, lbl, net; + quint32 tre, rgn, lbl, net, nod; if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre) && _gmp->readUInt32(hdl, rgn) && _gmp->readUInt32(hdl, lbl) - && _gmp->readUInt32(hdl, net))) + && _gmp->readUInt32(hdl, net) && _gmp->readUInt32(hdl, nod))) return false; _tre = tre ? new TREFile(_gmp, tre) : 0; _rgn = rgn ? new RGNFile(_gmp, rgn) : 0; _lbl = lbl ? new LBLFile(_gmp, lbl) : 0; _net = net ? new NETFile(_gmp, net) : 0; + _nod = nod ? new NODFile(_gmp, nod) : 0; return true; } @@ -115,7 +124,7 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap, QList *polygons, QList *lines, QCache *polyCache) const { - SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net); + SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net), nodHdl(_nod); if (!_rgn->initialized() && !_rgn->init(rgnHdl)) return; @@ -140,6 +149,7 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap, lblHdl, &p); _rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl, lblHdl, &l); + _rgn->links(rgnHdl, subdiv, _net, netHdl, _nod, nodHdl, &l); copyPolys(rect, &p, polygons); copyPolys(rect, &l, lines); diff --git a/src/map/IMG/vectortile.h b/src/map/IMG/vectortile.h index b63cf174..7442e088 100644 --- a/src/map/IMG/vectortile.h +++ b/src/map/IMG/vectortile.h @@ -6,13 +6,15 @@ #include "rgnfile.h" #include "lblfile.h" #include "netfile.h" +#include "nodfile.h" class VectorTile { public: - VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {} + VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _nod(0), _gmp(0) {} ~VectorTile() { - delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp; + delete _tre; delete _rgn; delete _lbl; delete _net; delete _nod; + delete _gmp; } bool init(); @@ -37,7 +39,7 @@ public: { return (type == SubFile::TRE || type == SubFile::LBL || type == SubFile::RGN || type == SubFile::NET - || type == SubFile::GMP); + || type == SubFile::NOD || type == SubFile::GMP); } private: @@ -47,6 +49,7 @@ private: RGNFile *_rgn; LBLFile *_lbl; NETFile *_net; + NODFile *_nod; SubFile *_gmp; };