mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-24 11:45:53 +01:00
Initial (and partial) IMG links support
+ various IMG fixes (RGN parsing, IMG parsing)
This commit is contained in:
parent
e7729e8745
commit
32d3eab10e
@ -95,6 +95,7 @@ HEADERS += src/common/config.h \
|
|||||||
src/map/IMG/gmap.h \
|
src/map/IMG/gmap.h \
|
||||||
src/map/IMG/huffmanstream.h \
|
src/map/IMG/huffmanstream.h \
|
||||||
src/map/IMG/huffmantable.h \
|
src/map/IMG/huffmantable.h \
|
||||||
|
src/map/IMG/nodfile.h \
|
||||||
src/map/IMG/mapdata.h \
|
src/map/IMG/mapdata.h \
|
||||||
src/map/IMG/rastertile.h \
|
src/map/IMG/rastertile.h \
|
||||||
src/map/IMG/textpathitem.h \
|
src/map/IMG/textpathitem.h \
|
||||||
@ -257,6 +258,7 @@ SOURCES += src/main.cpp \
|
|||||||
src/map/IMG/gmap.cpp \
|
src/map/IMG/gmap.cpp \
|
||||||
src/map/IMG/huffmanstream.cpp \
|
src/map/IMG/huffmanstream.cpp \
|
||||||
src/map/IMG/huffmantable.cpp \
|
src/map/IMG/huffmantable.cpp \
|
||||||
|
src/map/IMG/nodfile.cpp \
|
||||||
src/map/IMG/mapdata.cpp \
|
src/map/IMG/mapdata.cpp \
|
||||||
src/map/IMG/rastertile.cpp \
|
src/map/IMG/rastertile.cpp \
|
||||||
src/map/IMG/textpathitem.cpp \
|
src/map/IMG/textpathitem.cpp \
|
||||||
|
@ -41,8 +41,19 @@ bool BitStream1::flush()
|
|||||||
return true;
|
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)) {
|
if (bits <= 32 - (int)(_used + _unused)) {
|
||||||
val = bits ? (_data << _used) >> (32 - bits) : 0;
|
val = bits ? (_data << _used) >> (32 - bits) : 0;
|
||||||
@ -50,6 +61,8 @@ bool BitStream4::read(int bits, quint32 &val)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_unused)
|
||||||
|
return false;
|
||||||
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
|
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
|
||||||
quint32 bytes = qMin(_length, 4U);
|
quint32 bytes = qMin(_length, 4U);
|
||||||
|
|
||||||
@ -66,14 +79,123 @@ bool BitStream4::read(int bits, quint32 &val)
|
|||||||
return true;
|
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;
|
return false;
|
||||||
|
|
||||||
_length = 0;
|
if ((b & 1) == 0) {
|
||||||
_used = 32;
|
if ((b & 2) == 0) {
|
||||||
_unused = 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;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ public:
|
|||||||
|
|
||||||
bool read(int bits, quint32 &val);
|
bool read(int bits, quint32 &val);
|
||||||
bool flush();
|
bool flush();
|
||||||
quint32 bitsAvailable() const {return _length * 8 + _remaining;}
|
quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SubFile &_file;
|
const SubFile &_file;
|
||||||
@ -25,15 +25,64 @@ public:
|
|||||||
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
|
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
|
||||||
_data(0) {}
|
_data(0) {}
|
||||||
|
|
||||||
bool read(int bits, quint32 &val);
|
|
||||||
bool flush();
|
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;
|
const SubFile &_file;
|
||||||
SubFile::Handle &_hdl;
|
SubFile::Handle &_hdl;
|
||||||
quint32 _length, _used, _unused;
|
quint32 _length, _used, _unused;
|
||||||
quint32 _data;
|
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<typename T> 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<typename T>
|
||||||
|
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
|
#endif // BITSTREAM_H
|
||||||
|
@ -1,74 +1,30 @@
|
|||||||
#include "huffmanstream.h"
|
#include "huffmanstream.h"
|
||||||
|
|
||||||
|
bool HuffmanStreamF::init(bool line)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (line) {
|
if (line) {
|
||||||
if (!(sign(_lonSign) && sign(_latSign)))
|
if (!(sign(_lonSign) && sign(_latSign)))
|
||||||
return;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
_lonSign = 0;
|
_lonSign = 0;
|
||||||
_latSign = 0;
|
_latSign = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 eb;
|
quint32 eb;
|
||||||
if (!read(1, eb))
|
if (!_bs.read(1, eb))
|
||||||
return;
|
return false;
|
||||||
if (eb) {
|
if (eb) {
|
||||||
qWarning("Extended polygon/lines not supported");
|
qWarning() << "Extended lines/polygons not supported";
|
||||||
flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HuffmanStream::sign(int &val)
|
|
||||||
{
|
|
||||||
quint32 bit;
|
|
||||||
val = 0;
|
|
||||||
|
|
||||||
if (!read(1, bit))
|
|
||||||
return false;
|
return false;
|
||||||
if (bit) {
|
|
||||||
if (!read(1, bit))
|
|
||||||
return false;
|
|
||||||
val = bit ? -1 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HuffmanStream::readDelta(int sign, qint32 &symbol)
|
bool HuffmanStreamR::init()
|
||||||
{
|
{
|
||||||
quint8 size;
|
if (!(sign(_lonSign) && sign(_latSign)))
|
||||||
quint32 next;
|
|
||||||
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize), bitsAvailable());
|
|
||||||
|
|
||||||
if (!read(nextSize, next))
|
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
#include "bitstream.h"
|
#include "bitstream.h"
|
||||||
#include "huffmantable.h"
|
#include "huffmantable.h"
|
||||||
|
|
||||||
class HuffmanStream : public BitStream4 {
|
template <class BitStream>
|
||||||
|
class HuffmanStream {
|
||||||
public:
|
public:
|
||||||
HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length,
|
HuffmanStream(BitStream &bitstream, const HuffmanTable &table)
|
||||||
const HuffmanTable &table, bool line);
|
: _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0),
|
||||||
|
_lonSign(0), _latSign(0) {}
|
||||||
|
|
||||||
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
||||||
{
|
{
|
||||||
@ -17,19 +19,87 @@ public:
|
|||||||
return (lonDelta || latDelta);
|
return (lonDelta || latDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readOffset(qint32 &lonDelta, qint32 &latDelta)
|
|
||||||
{return (readDelta(1, lonDelta) && readDelta(1, latDelta));}
|
|
||||||
bool atEnd() const
|
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 sign(int &val);
|
||||||
bool readDelta(int sign, qint32 &delta);
|
bool readDelta(int sign, qint32 &delta);
|
||||||
|
|
||||||
|
BitStream &_bs;
|
||||||
const HuffmanTable &_table;
|
const HuffmanTable &_table;
|
||||||
quint32 _symbolDataSize;
|
quint32 _symbolDataSize;
|
||||||
quint32 _symbolData;
|
quint32 _symbolData;
|
||||||
int _lonSign, _latSign;
|
int _lonSign, _latSign;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class BitStream>
|
||||||
|
bool HuffmanStream<BitStream>::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 <class BitStream>
|
||||||
|
bool HuffmanStream<BitStream>::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<BitStream4F> {
|
||||||
|
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<BitStream4R> {
|
||||||
|
public:
|
||||||
|
HuffmanStreamR(BitStream4R &bitstream, const HuffmanTable &table)
|
||||||
|
: HuffmanStream(bitstream, table) {}
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
};
|
||||||
|
|
||||||
#endif // HUFFMANSTREAM_H
|
#endif // HUFFMANSTREAM_H
|
||||||
|
@ -42,6 +42,8 @@ bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl,
|
|||||||
_s10 = _s14 + _s1c * _s1d;
|
_s10 = _s14 + _s1c * _s1d;
|
||||||
_s18 = _s10 + (_s1 << _s0);
|
_s18 = _s10 + (_s1 << _s0);
|
||||||
|
|
||||||
|
_id = id;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ public:
|
|||||||
quint8 maxSymbolSize() const {return _s2;}
|
quint8 maxSymbolSize() const {return _s2;}
|
||||||
quint32 symbol(quint32 data, quint8 &size) const;
|
quint32 symbol(quint32 data, quint8 &size) const;
|
||||||
|
|
||||||
|
quint8 id() const {return _id;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset,
|
bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset,
|
||||||
quint32 size, quint8 id);
|
quint32 size, quint8 id);
|
||||||
@ -22,6 +24,8 @@ private:
|
|||||||
quint8 *_s10, *_s14, *_s18;
|
quint8 *_s10, *_s14, *_s18;
|
||||||
quint8 _s1c, _s1d, _s1e, _s1f, _s20;
|
quint8 _s1c, _s1d, _s1e, _s1f, _s20;
|
||||||
quint16 _s22;
|
quint16 _s22;
|
||||||
|
|
||||||
|
quint8 _id;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HUFFMANTABLE_H
|
#endif // HUFFMANTABLE_H
|
||||||
|
@ -59,7 +59,7 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
|||||||
|
|
||||||
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
|
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
|
||||||
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
|
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
|
||||||
_blockSize = 1 << (e1 + e2);
|
_blockBits = e1 + e2;
|
||||||
|
|
||||||
// Read the FAT table
|
// Read the FAT table
|
||||||
quint8 flag;
|
quint8 flag;
|
||||||
@ -132,7 +132,6 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create tile tree
|
// Create tile tree
|
||||||
|
|
||||||
int minMapZoom = 24;
|
int minMapZoom = 24;
|
||||||
for (TileMap::const_iterator it = tileMap.constBegin();
|
for (TileMap::const_iterator it = tileMap.constBegin();
|
||||||
it != tileMap.constEnd(); ++it) {
|
it != tileMap.constEnd(); ++it) {
|
||||||
@ -159,14 +158,19 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
|||||||
minMapZoom = tile->zooms().min();
|
minMapZoom = tile->zooms().min();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TileMap::const_iterator it = tileMap.constBegin();
|
// Detect and mark basemap
|
||||||
it != tileMap.constEnd(); ++it) {
|
TileTree::Iterator it;
|
||||||
VectorTile *tile = it.value();
|
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) {
|
||||||
|
VectorTile *tile = _tileTree.GetAt(it);
|
||||||
if (tile->zooms().min() > minMapZoom)
|
if (tile->zooms().min() > minMapZoom)
|
||||||
_baseMap = true;
|
_baseMap = true;
|
||||||
if (tile->zooms().min() == minMapZoom)
|
if (tile->zooms().min() == minMapZoom)
|
||||||
tile->markAsBasemap();
|
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())
|
if (!_tileTree.Count())
|
||||||
_errorString = "No usable map tile found";
|
_errorString = "No usable map tile found";
|
||||||
@ -197,9 +201,9 @@ template<class T> bool IMG::readValue(T &val)
|
|||||||
|
|
||||||
bool IMG::readBlock(int blockNum, char *data)
|
bool IMG::readBlock(int blockNum, char *data)
|
||||||
{
|
{
|
||||||
if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
|
if (!_file.seek((quint64)blockNum << _blockBits))
|
||||||
return false;
|
return false;
|
||||||
if (read(data, _blockSize) < _blockSize)
|
if (read(data, 1U<<_blockBits) < 1U<<_blockBits)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -14,14 +14,14 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class SubFile;
|
friend class SubFile;
|
||||||
|
|
||||||
int blockSize() const {return _blockSize;}
|
unsigned blockBits() const {return _blockBits;}
|
||||||
bool readBlock(int blockNum, char *data);
|
bool readBlock(int blockNum, char *data);
|
||||||
qint64 read(char *data, qint64 maxSize);
|
qint64 read(char *data, qint64 maxSize);
|
||||||
template<class T> bool readValue(T &val);
|
template<class T> bool readValue(T &val);
|
||||||
|
|
||||||
QFile _file;
|
QFile _file;
|
||||||
quint8 _key;
|
quint8 _key;
|
||||||
int _blockSize;
|
unsigned _blockBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMG_H
|
#endif // IMG_H
|
||||||
|
@ -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)
|
_valid(false)
|
||||||
{
|
{
|
||||||
_polyCache.setMaxCost(CACHED_SUBDIVS_COUNT);
|
_polyCache.setMaxCost(CACHED_SUBDIVS_COUNT);
|
||||||
|
@ -1,5 +1,89 @@
|
|||||||
|
#include "bitstream.h"
|
||||||
|
#include "huffmanstream.h"
|
||||||
|
#include "subdiv.h"
|
||||||
|
#include "nodfile.h"
|
||||||
#include "netfile.h"
|
#include "netfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool adjCnts(BitStream4R &bs, QVector<quint16> &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<quint16> &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)
|
bool NETFile::init(Handle &hdl)
|
||||||
{
|
{
|
||||||
quint8 multiplier;
|
quint8 multiplier;
|
||||||
@ -10,11 +94,121 @@ bool NETFile::init(Handle &hdl)
|
|||||||
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)))
|
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)))
|
||||||
return false;
|
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<<multiplier;
|
_multiplier = 1<<multiplier;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
|
||||||
|
Handle &nodHdl, const NODFile::BlockInfo blockInfo, quint8 linkId,
|
||||||
|
quint8 lineId, const HuffmanTable &table, QList<IMG::Poly> *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<quint16> 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)
|
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset)
|
||||||
{
|
{
|
||||||
if (!_multiplier && !init(hdl))
|
if (!_multiplier && !init(hdl))
|
||||||
|
@ -1,25 +1,37 @@
|
|||||||
#ifndef NETFILE_H
|
#ifndef NETFILE_H
|
||||||
#define NETFILE_H
|
#define NETFILE_H
|
||||||
|
|
||||||
|
#include "img.h"
|
||||||
#include "subfile.h"
|
#include "subfile.h"
|
||||||
|
#include "nodfile.h"
|
||||||
|
|
||||||
|
class NODFile;
|
||||||
|
class LBLFile;
|
||||||
|
class SubDiv;
|
||||||
|
class HuffmanTable;
|
||||||
|
|
||||||
class NETFile : public SubFile
|
class NETFile : public SubFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NETFile(IMG *img)
|
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0),
|
||||||
: SubFile(img), _offset(0), _size(0), _multiplier(0) {}
|
_linksSize(0), _multiplier(0), _linksShift(0) {}
|
||||||
NETFile(const QString &path)
|
NETFile(const QString &path) : SubFile(path), _offset(0), _size(0),
|
||||||
: SubFile(path), _offset(0), _size(0), _multiplier(0) {}
|
_linksOffset(0), _linksSize(0), _multiplier(0), _linksShift(0) {}
|
||||||
NETFile(SubFile *gmp, quint32 offset)
|
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||||
: SubFile(gmp, offset), _offset(0), _size(0), _multiplier(0) {}
|
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _multiplier(0),
|
||||||
|
_linksShift(0) {}
|
||||||
|
|
||||||
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
|
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<IMG::Poly> *lines);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool init(Handle &hdl);
|
bool init(Handle &hdl);
|
||||||
|
|
||||||
quint32 _offset, _size;
|
quint32 _offset, _size, _linksOffset, _linksSize;
|
||||||
quint8 _multiplier;
|
quint8 _multiplier, _linksShift;
|
||||||
|
quint8 _tableId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NETFILE_H
|
#endif // NETFILE_H
|
||||||
|
155
src/map/IMG/nodfile.cpp
Normal file
155
src/map/IMG/nodfile.cpp
Normal file
@ -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;
|
||||||
|
}
|
55
src/map/IMG/nodfile.h
Normal file
55
src/map/IMG/nodfile.h
Normal file
@ -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
|
@ -5,9 +5,12 @@
|
|||||||
#include "huffmanstream.h"
|
#include "huffmanstream.h"
|
||||||
#include "lblfile.h"
|
#include "lblfile.h"
|
||||||
#include "netfile.h"
|
#include "netfile.h"
|
||||||
|
#include "nodfile.h"
|
||||||
#include "rgnfile.h"
|
#include "rgnfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MASK(bits) ((2U << ((bits) - 1U)) - 1U)
|
||||||
|
|
||||||
static quint64 pointId(const QPoint &pos, quint32 type, quint32 labelPtr)
|
static quint64 pointId(const QPoint &pos, quint32 type, quint32 labelPtr)
|
||||||
{
|
{
|
||||||
quint64 id;
|
quint64 id;
|
||||||
@ -52,8 +55,7 @@ bool RGNFile::skipClassFields(Handle &hdl) const
|
|||||||
return seek(hdl, hdl.pos() + rs);
|
return seek(hdl, hdl.pos() + rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
|
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3]) const
|
||||||
SegmentType type) const
|
|
||||||
{
|
{
|
||||||
quint32 bitfield = 0xFFFFFFFF;
|
quint32 bitfield = 0xFFFFFFFF;
|
||||||
|
|
||||||
@ -61,29 +63,40 @@ bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
|
|||||||
if (!readVBitfield32(hdl, bitfield))
|
if (!readVBitfield32(hdl, bitfield))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (int i = 0; i < 29; i++) {
|
for (int i = 0, j = 0; i < 29; i++) {
|
||||||
if ((flags[0] >> i) & 1) {
|
if ((flags[0] >> i) & 1) {
|
||||||
if (bitfield & 1) {
|
if (bitfield & 1) {
|
||||||
quint32 m = flags[(i >> 4) + 1] >> ((i * 2) & 0x1e) & 3;
|
quint32 m = flags[(j >> 4) + 1] >> ((j * 2) & 0x1e) & 3;
|
||||||
switch (i) {
|
|
||||||
case 5:
|
quint32 skip = 0;
|
||||||
if (m == 1 && type == Point) {
|
if (m == 3) {
|
||||||
quint16 u16;
|
if (!readVUInt32(hdl, skip))
|
||||||
if (!readUInt16(hdl, u16))
|
return false;
|
||||||
|
} else
|
||||||
|
skip = m + 1;
|
||||||
|
if (!seek(hdl, hdl.pos() + skip))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bitfield >>= 1;
|
bitfield >>= 1;
|
||||||
|
j++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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()
|
void RGNFile::clearFlags()
|
||||||
{
|
{
|
||||||
memset(_polygonsFlags, 0, sizeof(_polygonsFlags));
|
memset(_polygonsFlags, 0, sizeof(_polygonsFlags));
|
||||||
@ -102,14 +115,17 @@ bool RGNFile::init(Handle &hdl)
|
|||||||
|
|
||||||
if (hdrLen >= 0x68) {
|
if (hdrLen >= 0x68) {
|
||||||
if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize)
|
if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize)
|
||||||
&& seek(hdl, _gmpOffset + 0x2D) && readUInt32(hdl, _polygonsFlags[0])
|
&& seek(hdl, _gmpOffset + 0x29) && readUInt32(hdl, _polygonGblFlags)
|
||||||
&& readUInt32(hdl, _polygonsFlags[1]) && readUInt32(hdl, _polygonsFlags[2])
|
&& readUInt32(hdl, _polygonsFlags[0]) && readUInt32(hdl, _polygonsFlags[1])
|
||||||
|
&& readUInt32(hdl, _polygonsFlags[2])
|
||||||
&& readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize)
|
&& readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize)
|
||||||
&& seek(hdl, _gmpOffset + 0x49) && readUInt32(hdl, _linesFlags[0])
|
&& seek(hdl, _gmpOffset + 0x45) && readUInt32(hdl, _linesGblFlags)
|
||||||
&& readUInt32(hdl, _linesFlags[1]) && readUInt32(hdl, _linesFlags[2])
|
&& readUInt32(hdl, _linesFlags[0]) && readUInt32(hdl, _linesFlags[1])
|
||||||
|
&& readUInt32(hdl, _linesFlags[2])
|
||||||
&& readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize)
|
&& readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize)
|
||||||
&& seek(hdl, _gmpOffset + 0x65) && readUInt32(hdl, _pointsFlags[0])
|
&& seek(hdl, _gmpOffset + 0x61) && readUInt32(hdl, _pointsGblFlags)
|
||||||
&& readUInt32(hdl, _pointsFlags[1]) && readUInt32(hdl, _pointsFlags[2])))
|
&& readUInt32(hdl, _pointsFlags[0]) && readUInt32(hdl, _pointsFlags[1])
|
||||||
|
&& readUInt32(hdl, _pointsFlags[2])))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,6 +246,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
|
|||||||
&& readInt16(hdl, lon) && readInt16(hdl, lat)
|
&& readInt16(hdl, lon) && readInt16(hdl, lat)
|
||||||
&& readVUInt32(hdl, len)))
|
&& readVUInt32(hdl, len)))
|
||||||
return false;
|
return false;
|
||||||
|
Q_ASSERT(hdl.pos() + len <= segment.end());
|
||||||
|
|
||||||
poly.type = 0x10000 | (quint16(type)<<8) | (subtype & 0x1F);
|
poly.type = 0x10000 | (quint16(type)<<8) | (subtype & 0x1F);
|
||||||
labelPtr = 0;
|
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())));
|
LS(subdiv->lat(), 8) + LS(lat, (32-subdiv->bits())));
|
||||||
|
|
||||||
qint32 lonDelta, latDelta;
|
qint32 lonDelta, latDelta;
|
||||||
HuffmanStream stream(*this, hdl, len, _huffmanTable,
|
BitStream4F bs(*this, hdl, len);
|
||||||
segmentType == Line);
|
HuffmanStreamF stream(bs, _huffmanTable);
|
||||||
|
if (!stream.init(segmentType == Line))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (shift) {
|
if (shift) {
|
||||||
if (!stream.readOffset(lonDelta, latDelta))
|
if (!stream.readOffset(lonDelta, latDelta))
|
||||||
@ -298,7 +317,11 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
|
|||||||
if (subtype & 0x80 && !skipClassFields(hdl))
|
if (subtype & 0x80 && !skipClassFields(hdl))
|
||||||
return false;
|
return false;
|
||||||
if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line
|
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;
|
return false;
|
||||||
|
|
||||||
if (lbl && (labelPtr & 0x3FFFFF))
|
if (lbl && (labelPtr & 0x3FFFFF))
|
||||||
@ -317,6 +340,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
|
|||||||
const SubDiv::Segment &segment = (segmentType == IndexedPoint)
|
const SubDiv::Segment &segment = (segmentType == IndexedPoint)
|
||||||
? subdiv->idxPoints() : subdiv->points();
|
? subdiv->idxPoints() : subdiv->points();
|
||||||
|
|
||||||
|
|
||||||
if (!segment.isValid())
|
if (!segment.isValid())
|
||||||
return true;
|
return true;
|
||||||
if (!seek(hdl, segment.offset()))
|
if (!seek(hdl, segment.offset()))
|
||||||
@ -379,7 +403,9 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
|||||||
return false;
|
return false;
|
||||||
if (subtype & 0x80 && !skipClassFields(hdl))
|
if (subtype & 0x80 && !skipClassFields(hdl))
|
||||||
return false;
|
return false;
|
||||||
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, Point))
|
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags))
|
||||||
|
return false;
|
||||||
|
if (_pointsGblFlags && !skipGblFields(hdl, _pointsGblFlags))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()),
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net,
|
||||||
|
Handle &netHdl, NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *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::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl,
|
QMap<RGNFile::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl,
|
||||||
SubDiv *subdiv) const
|
SubDiv *subdiv) const
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
class LBLFile;
|
class LBLFile;
|
||||||
class NETFile;
|
class NETFile;
|
||||||
|
class NODFile;
|
||||||
|
|
||||||
class RGNFile : public SubFile
|
class RGNFile : public SubFile
|
||||||
{
|
{
|
||||||
@ -46,6 +47,8 @@ public:
|
|||||||
QList<IMG::Poly> *polys) const;
|
QList<IMG::Poly> *polys) const;
|
||||||
bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
||||||
Handle &lblHdl, QList<IMG::Point> *points) const;
|
Handle &lblHdl, QList<IMG::Point> *points) const;
|
||||||
|
bool links(Handle &hdl, const SubDiv *subdiv, NETFile *net, Handle &netHdl,
|
||||||
|
NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const;
|
||||||
|
|
||||||
bool subdivInit(Handle &hdl, SubDiv *subdiv) const;
|
bool subdivInit(Handle &hdl, SubDiv *subdiv) const;
|
||||||
|
|
||||||
@ -54,8 +57,9 @@ private:
|
|||||||
const;
|
const;
|
||||||
void clearFlags();
|
void clearFlags();
|
||||||
bool skipClassFields(Handle &hdl) const;
|
bool skipClassFields(Handle &hdl) const;
|
||||||
bool skipLclFields(Handle &hdl, const quint32 flags[3], SegmentType type)
|
bool skipLclFields(Handle &hdl, const quint32 flags[3])
|
||||||
const;
|
const;
|
||||||
|
bool skipGblFields(Handle &hdl, quint32 flags) const;
|
||||||
|
|
||||||
quint32 _offset;
|
quint32 _offset;
|
||||||
quint32 _size;
|
quint32 _size;
|
||||||
@ -69,6 +73,9 @@ private:
|
|||||||
quint32 _pointsOffset;
|
quint32 _pointsOffset;
|
||||||
quint32 _pointsSize;
|
quint32 _pointsSize;
|
||||||
quint32 _pointsFlags[3];
|
quint32 _pointsFlags[3];
|
||||||
|
quint32 _polygonGblFlags;
|
||||||
|
quint32 _linesGblFlags;
|
||||||
|
quint32 _pointsGblFlags;
|
||||||
|
|
||||||
HuffmanTable _huffmanTable;
|
HuffmanTable _huffmanTable;
|
||||||
|
|
||||||
|
@ -21,8 +21,9 @@ public:
|
|||||||
quint32 _offset, _end;
|
quint32 _offset, _end;
|
||||||
};
|
};
|
||||||
|
|
||||||
SubDiv(quint32 offset, qint32 lon, qint32 lat, int bits, quint8 objects)
|
SubDiv(quint32 offset, qint32 lon, qint32 lat, quint8 level, quint8 bits,
|
||||||
: _lon(lon), _lat(lat), _bits(bits), _init(false)
|
quint8 objects) : _lon(lon), _lat(lat), _level(level), _bits(bits),
|
||||||
|
_init(false)
|
||||||
{
|
{
|
||||||
_tre.objects = objects;
|
_tre.objects = objects;
|
||||||
_tre.offset = offset;
|
_tre.offset = offset;
|
||||||
@ -78,6 +79,7 @@ public:
|
|||||||
qint32 lon() const {return _lon;}
|
qint32 lon() const {return _lon;}
|
||||||
qint32 lat() const {return _lat;}
|
qint32 lat() const {return _lat;}
|
||||||
quint8 bits() const {return _bits;}
|
quint8 bits() const {return _bits;}
|
||||||
|
quint8 level() const {return _level;}
|
||||||
|
|
||||||
// Valid only after initialization
|
// Valid only after initialization
|
||||||
Segment points() const
|
Segment points() const
|
||||||
@ -94,6 +96,8 @@ public:
|
|||||||
{return Segment(_rgn.extLinesOffset, _rgn.extLinesEnd);}
|
{return Segment(_rgn.extLinesOffset, _rgn.extLinesEnd);}
|
||||||
Segment extPolygons() const
|
Segment extPolygons() const
|
||||||
{return Segment(_rgn.extPolygonsOffset, _rgn.extPolygonsEnd);}
|
{return Segment(_rgn.extPolygonsOffset, _rgn.extPolygonsEnd);}
|
||||||
|
Segment roadReferences() const
|
||||||
|
{return Segment(_rgn.roadReferencesOffset, _rgn.roadReferencesEnd);}
|
||||||
|
|
||||||
// Valid only until initialization
|
// Valid only until initialization
|
||||||
quint8 objects() const {return _tre.objects;}
|
quint8 objects() const {return _tre.objects;}
|
||||||
@ -142,6 +146,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
qint32 _lon, _lat;
|
qint32 _lon, _lat;
|
||||||
|
quint8 _level;
|
||||||
quint8 _bits;
|
quint8 _bits;
|
||||||
bool _init;
|
bool _init;
|
||||||
union {
|
union {
|
||||||
|
@ -3,26 +3,28 @@
|
|||||||
#include "subfile.h"
|
#include "subfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define mod2n(x, m) ((x) & ((m) - 1));
|
||||||
|
|
||||||
bool SubFile::seek(Handle &handle, quint32 pos) const
|
bool SubFile::seek(Handle &handle, quint32 pos) const
|
||||||
{
|
{
|
||||||
if (handle._file) {
|
if (handle._file) {
|
||||||
int blockNum = pos / BLOCK_SIZE;
|
int blockNum = pos >> BLOCK_BITS;
|
||||||
|
|
||||||
if (handle._blockNum != blockNum) {
|
if (handle._blockNum != blockNum) {
|
||||||
if (!handle._file->seek((qint64)blockNum * BLOCK_SIZE))
|
if (!handle._file->seek((quint64)blockNum << BLOCK_BITS))
|
||||||
return false;
|
return false;
|
||||||
if (handle._file->read(handle._data.data(), BLOCK_SIZE) < 0)
|
if (handle._file->read(handle._data.data(), (1<<BLOCK_BITS)) < 0)
|
||||||
return false;
|
return false;
|
||||||
handle._blockNum = blockNum;
|
handle._blockNum = blockNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle._blockPos = pos % BLOCK_SIZE;
|
handle._blockPos = mod2n(pos, 1U<<BLOCK_BITS);
|
||||||
handle._pos = pos;
|
handle._pos = pos;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
quint32 blockSize = _img->blockSize();
|
quint32 blockBits = _img->blockBits();
|
||||||
int blockNum = pos / blockSize;
|
int blockNum = pos >> blockBits;
|
||||||
|
|
||||||
if (handle._blockNum != blockNum) {
|
if (handle._blockNum != blockNum) {
|
||||||
if (blockNum >= _blocks->size())
|
if (blockNum >= _blocks->size())
|
||||||
@ -32,7 +34,7 @@ bool SubFile::seek(Handle &handle, quint32 pos) const
|
|||||||
handle._blockNum = blockNum;
|
handle._blockNum = blockNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle._blockPos = pos % blockSize;
|
handle._blockPos = mod2n(pos, 1U<<blockBits);
|
||||||
handle._pos = pos;
|
handle._pos = pos;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -70,6 +72,22 @@ bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SubFile::readVUInt32(Handle &hdl, quint32 bytes, quint32 &val) const
|
||||||
|
{
|
||||||
|
switch (bytes) {
|
||||||
|
case 1:
|
||||||
|
return readUInt8(hdl, val);
|
||||||
|
case 2:
|
||||||
|
return readUInt16(hdl, val);
|
||||||
|
case 3:
|
||||||
|
return readUInt24(hdl, val);
|
||||||
|
case 4:
|
||||||
|
return readUInt32(hdl, val);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
|
bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
|
||||||
{
|
{
|
||||||
quint8 bits;
|
quint8 bits;
|
||||||
|
@ -6,12 +6,12 @@
|
|||||||
#include "img.h"
|
#include "img.h"
|
||||||
|
|
||||||
|
|
||||||
#define BLOCK_SIZE 4096
|
#define BLOCK_BITS 12 /* 4096 bytes */
|
||||||
|
|
||||||
class SubFile
|
class SubFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Type {Unknown, TRE, RGN, LBL, NET, TYP, GMP};
|
enum Type {Unknown, TRE, RGN, LBL, NET, NOD, TYP, GMP};
|
||||||
|
|
||||||
class Handle
|
class Handle
|
||||||
{
|
{
|
||||||
@ -22,9 +22,9 @@ public:
|
|||||||
if (subFile && subFile->_path) {
|
if (subFile && subFile->_path) {
|
||||||
_file = new QFile(*(subFile->_path));
|
_file = new QFile(*(subFile->_path));
|
||||||
_file->open(QIODevice::ReadOnly);
|
_file->open(QIODevice::ReadOnly);
|
||||||
_data.resize(BLOCK_SIZE);
|
_data.resize(1U<<BLOCK_BITS);
|
||||||
} else if (subFile)
|
} else if (subFile)
|
||||||
_data.resize(subFile->_img->blockSize());
|
_data.resize(1U<<subFile->_img->blockBits());
|
||||||
}
|
}
|
||||||
~Handle() {delete _file;}
|
~Handle() {delete _file;}
|
||||||
|
|
||||||
@ -132,6 +132,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool readVUInt32(Handle &hdl, quint32 &val) const;
|
bool readVUInt32(Handle &hdl, quint32 &val) const;
|
||||||
|
bool readVUInt32(Handle &hdl, quint32 bytes, quint32 &val) const;
|
||||||
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
|
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
|
||||||
|
|
||||||
QString fileName() const {return _path ? *_path : _img->fileName();}
|
QString fileName() const {return _path ? *_path : _img->fileName();}
|
||||||
@ -142,7 +143,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
bool readByte(Handle &handle, quint8 &val) const
|
bool readByte(Handle &handle, quint8 &val) const
|
||||||
{
|
{
|
||||||
int blockSize = _img ? _img->blockSize() : BLOCK_SIZE;
|
int blockSize = _img ? 1U<<_img->blockBits() : 1U<<BLOCK_BITS;
|
||||||
val = handle._data.at(handle._blockPos++);
|
val = handle._data.at(handle._blockPos++);
|
||||||
handle._pos++;
|
handle._pos++;
|
||||||
return (handle._blockPos >= blockSize)
|
return (handle._blockPos >= blockSize)
|
||||||
|
@ -70,14 +70,16 @@ bool TREFile::init()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (hdrLen > 0x9A) {
|
if (hdrLen > 0x9A) {
|
||||||
// TRE7 info
|
// TRE7 info + flags
|
||||||
if (!(seek(hdl, _gmpOffset + 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) && readUInt32(hdl, _flags)))
|
||||||
return false;
|
|
||||||
// flags
|
|
||||||
if (!(seek(hdl, _gmpOffset + 0x86) && readUInt32(hdl, _flags)))
|
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
_extended.offset = 0;
|
||||||
|
_extended.size = 0;
|
||||||
|
_extended.itemSize = 0;
|
||||||
|
_flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tile levels
|
// Tile levels
|
||||||
@ -126,9 +128,10 @@ bool TREFile::load(int idx)
|
|||||||
QList<SubDiv*> sl;
|
QList<SubDiv*> sl;
|
||||||
SubDiv *s = 0;
|
SubDiv *s = 0;
|
||||||
SubDivTree *tree = new SubDivTree();
|
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;
|
quint32 skip = 0;
|
||||||
for (int i = 0; i < idx; i++)
|
for (int i = 0; i < idx; i++)
|
||||||
@ -137,7 +140,7 @@ bool TREFile::load(int idx)
|
|||||||
if (!seek(hdl, _subdivOffset + skip * 16))
|
if (!seek(hdl, _subdivOffset + skip * 16))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (int j = 0; j < _levels.at(idx).subdivs; j++) {
|
for (int j = 0; j < level.subdivs; j++) {
|
||||||
quint32 oo;
|
quint32 oo;
|
||||||
qint32 lon, lat, width, height;
|
qint32 lon, lat, width, height;
|
||||||
quint16 nextLevel;
|
quint16 nextLevel;
|
||||||
@ -156,10 +159,10 @@ bool TREFile::load(int idx)
|
|||||||
s->setEnd(offset);
|
s->setEnd(offset);
|
||||||
|
|
||||||
width &= 0x7FFF;
|
width &= 0x7FFF;
|
||||||
width = LS(width, 24 - _levels.at(idx).bits);
|
width = LS(width, 24 - level.bits);
|
||||||
height = LS(height, 24 - _levels.at(idx).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);
|
sl.append(s);
|
||||||
|
|
||||||
double min[2], max[2];
|
double min[2], max[2];
|
||||||
@ -184,30 +187,40 @@ bool TREFile::load(int idx)
|
|||||||
|
|
||||||
|
|
||||||
// Objects with extended types (TRE7)
|
// Objects with extended types (TRE7)
|
||||||
if (_extended.size && _extended.itemSize >= 12) {
|
if (_extended.size && _extended.itemSize) {
|
||||||
/* 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. */
|
|
||||||
quint32 totalSubdivs = 0;
|
quint32 totalSubdivs = 0;
|
||||||
for (int i = 0; i < _levels.size(); i++)
|
for (int i = 0; i < _levels.size(); i++)
|
||||||
totalSubdivs += _levels.at(i).subdivs;
|
totalSubdivs += _levels.at(i).subdivs;
|
||||||
quint32 extendedSubdivs = _extended.size / _extended.itemSize;
|
quint32 extendedSubdivs = _extended.size / _extended.itemSize;
|
||||||
quint32 diff = totalSubdivs - extendedSubdivs + 1;
|
quint32 diff = totalSubdivs - extendedSubdivs + 1;
|
||||||
|
|
||||||
quint32 polygons, lines, points;
|
|
||||||
if (!seek(hdl, _extended.offset + (skip - diff) * _extended.itemSize))
|
if (!seek(hdl, _extended.offset + (skip - diff) * _extended.itemSize))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
quint32 polygons = 0, lines = 0, points = 0;
|
||||||
for (int i = 0; i < sl.size(); i++) {
|
for (int i = 0; i < sl.size(); i++) {
|
||||||
if (!(readUInt32(hdl, polygons) && readUInt32(hdl, lines)
|
quint32 rb = 0;
|
||||||
&& readUInt32(hdl, points)))
|
|
||||||
|
if (_flags & 1) {
|
||||||
|
if (!readUInt32(hdl, polygons))
|
||||||
goto error;
|
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);
|
sl.at(i)->setExtOffsets(polygons, lines, points);
|
||||||
if (i)
|
if (i)
|
||||||
sl.at(i-1)->setExtEnds(polygons, lines, points);
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ SubFile *VectorTile::file(SubFile::Type type)
|
|||||||
return _lbl;
|
return _lbl;
|
||||||
case SubFile::NET:
|
case SubFile::NET:
|
||||||
return _net;
|
return _net;
|
||||||
|
case SubFile::NOD:
|
||||||
|
return _nod;
|
||||||
case SubFile::GMP:
|
case SubFile::GMP:
|
||||||
return _gmp;
|
return _gmp;
|
||||||
default:
|
default:
|
||||||
@ -51,6 +53,9 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type)
|
|||||||
case SubFile::NET:
|
case SubFile::NET:
|
||||||
_net = new NETFile(img);
|
_net = new NETFile(img);
|
||||||
return _net;
|
return _net;
|
||||||
|
case SubFile::NOD:
|
||||||
|
_nod = new NODFile(img);
|
||||||
|
return _nod;
|
||||||
case SubFile::GMP:
|
case SubFile::GMP:
|
||||||
_gmp = new SubFile(img);
|
_gmp = new SubFile(img);
|
||||||
return _gmp;
|
return _gmp;
|
||||||
@ -74,6 +79,9 @@ SubFile *VectorTile::addFile(const QString &path, SubFile::Type type)
|
|||||||
case SubFile::NET:
|
case SubFile::NET:
|
||||||
_net = new NETFile(path);
|
_net = new NETFile(path);
|
||||||
return _net;
|
return _net;
|
||||||
|
case SubFile::NOD:
|
||||||
|
_nod = new NODFile(path);
|
||||||
|
return _nod;
|
||||||
case SubFile::GMP:
|
case SubFile::GMP:
|
||||||
_gmp = new SubFile(path);
|
_gmp = new SubFile(path);
|
||||||
return _gmp;
|
return _gmp;
|
||||||
@ -96,17 +104,18 @@ bool VectorTile::init()
|
|||||||
bool VectorTile::initGMP()
|
bool VectorTile::initGMP()
|
||||||
{
|
{
|
||||||
SubFile::Handle hdl(_gmp);
|
SubFile::Handle hdl(_gmp);
|
||||||
quint32 tre, rgn, lbl, net;
|
quint32 tre, rgn, lbl, net, nod;
|
||||||
|
|
||||||
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre)
|
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre)
|
||||||
&& _gmp->readUInt32(hdl, rgn) && _gmp->readUInt32(hdl, lbl)
|
&& _gmp->readUInt32(hdl, rgn) && _gmp->readUInt32(hdl, lbl)
|
||||||
&& _gmp->readUInt32(hdl, net)))
|
&& _gmp->readUInt32(hdl, net) && _gmp->readUInt32(hdl, nod)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_tre = tre ? new TREFile(_gmp, tre) : 0;
|
_tre = tre ? new TREFile(_gmp, tre) : 0;
|
||||||
_rgn = rgn ? new RGNFile(_gmp, rgn) : 0;
|
_rgn = rgn ? new RGNFile(_gmp, rgn) : 0;
|
||||||
_lbl = lbl ? new LBLFile(_gmp, lbl) : 0;
|
_lbl = lbl ? new LBLFile(_gmp, lbl) : 0;
|
||||||
_net = net ? new NETFile(_gmp, net) : 0;
|
_net = net ? new NETFile(_gmp, net) : 0;
|
||||||
|
_nod = nod ? new NODFile(_gmp, nod) : 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -115,7 +124,7 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
|
|||||||
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
|
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
|
||||||
QCache<const SubDiv *, IMG::Polys> *polyCache) const
|
QCache<const SubDiv *, IMG::Polys> *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))
|
if (!_rgn->initialized() && !_rgn->init(rgnHdl))
|
||||||
return;
|
return;
|
||||||
@ -140,6 +149,7 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
|
|||||||
lblHdl, &p);
|
lblHdl, &p);
|
||||||
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl,
|
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl,
|
||||||
lblHdl, &l);
|
lblHdl, &l);
|
||||||
|
_rgn->links(rgnHdl, subdiv, _net, netHdl, _nod, nodHdl, &l);
|
||||||
|
|
||||||
copyPolys(rect, &p, polygons);
|
copyPolys(rect, &p, polygons);
|
||||||
copyPolys(rect, &l, lines);
|
copyPolys(rect, &l, lines);
|
||||||
|
@ -6,13 +6,15 @@
|
|||||||
#include "rgnfile.h"
|
#include "rgnfile.h"
|
||||||
#include "lblfile.h"
|
#include "lblfile.h"
|
||||||
#include "netfile.h"
|
#include "netfile.h"
|
||||||
|
#include "nodfile.h"
|
||||||
|
|
||||||
class VectorTile {
|
class VectorTile {
|
||||||
public:
|
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()
|
~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();
|
bool init();
|
||||||
@ -37,7 +39,7 @@ public:
|
|||||||
{
|
{
|
||||||
return (type == SubFile::TRE || type == SubFile::LBL
|
return (type == SubFile::TRE || type == SubFile::LBL
|
||||||
|| type == SubFile::RGN || type == SubFile::NET
|
|| type == SubFile::RGN || type == SubFile::NET
|
||||||
|| type == SubFile::GMP);
|
|| type == SubFile::NOD || type == SubFile::GMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -47,6 +49,7 @@ private:
|
|||||||
RGNFile *_rgn;
|
RGNFile *_rgn;
|
||||||
LBLFile *_lbl;
|
LBLFile *_lbl;
|
||||||
NETFile *_net;
|
NETFile *_net;
|
||||||
|
NODFile *_nod;
|
||||||
SubFile *_gmp;
|
SubFile *_gmp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user