mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-28 05:34:47 +01:00
Level 0
This commit is contained in:
parent
0e026d6a96
commit
d738ad7b5a
@ -1,35 +1,6 @@
|
|||||||
#include "bitstream.h"
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
|
||||||
bool BitStream1::read(int bits, quint32 &val)
|
|
||||||
{
|
|
||||||
val = 0;
|
|
||||||
|
|
||||||
for (int pos = 0; pos < bits; ) {
|
|
||||||
if (!_remaining) {
|
|
||||||
if (!_length || !_file.readUInt8(_hdl, _data))
|
|
||||||
return false;
|
|
||||||
_remaining = 8;
|
|
||||||
_length--;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 get = bits - pos;
|
|
||||||
if (get >= _remaining) {
|
|
||||||
val |= _data << pos;
|
|
||||||
pos += _remaining;
|
|
||||||
_remaining = 0;
|
|
||||||
} else {
|
|
||||||
quint32 mask = (1<<get) - 1;
|
|
||||||
val |= (_data & mask)<<pos;
|
|
||||||
_data >>= get;
|
|
||||||
_remaining -= get;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BitStream1::flush()
|
bool BitStream1::flush()
|
||||||
{
|
{
|
||||||
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
|
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
|
||||||
@ -41,7 +12,7 @@ bool BitStream1::flush()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BitStream4::flush()
|
bool BitStream4F::flush()
|
||||||
{
|
{
|
||||||
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
|
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
|
||||||
return false;
|
return false;
|
||||||
@ -96,7 +67,14 @@ bool BitStream4R::readBytes(int bytes, quint32 &val)
|
|||||||
Q_ASSERT(!b);
|
Q_ASSERT(!b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return read(bytes * 8, val);
|
val = 0;
|
||||||
|
for (int i = 0; i < bytes; i++) {
|
||||||
|
if (!read(8, b))
|
||||||
|
return false;
|
||||||
|
val |= (b << (i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BitStream4R::readVUInt32(quint32 &val)
|
bool BitStream4R::readVUInt32(quint32 &val)
|
||||||
@ -139,7 +117,7 @@ bool BitStream4R::readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!(b & 1)) {
|
if (!(b & 1)) {
|
||||||
val1 = b >> 3 & 0x1f;
|
val1 = b >> 3;
|
||||||
val2 = b >> 1 & 3;
|
val2 = b >> 1 & 3;
|
||||||
val2Bits = 2;
|
val2Bits = 2;
|
||||||
} else {
|
} else {
|
||||||
@ -188,14 +166,33 @@ bool BitStream4R::skip(quint32 bytes)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitStream4R::resize(quint32 length)
|
void BitStream4R::resize(quint32 bytes)
|
||||||
{
|
{
|
||||||
quint32 ab = (32 - _used)/8;
|
quint32 ab = (32 - (_used + _unused) + 7)/8;
|
||||||
|
|
||||||
if (ab < length)
|
if (ab <= bytes)
|
||||||
_length = length - ab;
|
_length = bytes - ab;
|
||||||
else {
|
else {
|
||||||
_length = 0;
|
_length = 0;
|
||||||
_used += length * 8;
|
_unused += (ab - bytes) * 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BitStream4R::save(State &state)
|
||||||
|
{
|
||||||
|
state.pos = _file.pos(_hdl);
|
||||||
|
state.length = _length;
|
||||||
|
state.used = _used;
|
||||||
|
state.unused = _unused;
|
||||||
|
state.data = _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BitStream4R::restore(const State &state)
|
||||||
|
{
|
||||||
|
_length = state.length;
|
||||||
|
_used = state.used;
|
||||||
|
_unused = state.unused;
|
||||||
|
_data = state.data;
|
||||||
|
|
||||||
|
return _file.seek(_hdl, state.pos);
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@ public:
|
|||||||
BitStream1(const SubFile &file, SubFile::Handle &hdl, quint32 length)
|
BitStream1(const SubFile &file, SubFile::Handle &hdl, quint32 length)
|
||||||
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
|
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
|
||||||
|
|
||||||
bool read(int bits, quint32 &val);
|
template<typename T> bool read(int bits, T &val);
|
||||||
bool flush();
|
bool flush();
|
||||||
quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
|
quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
|
||||||
|
|
||||||
@ -25,7 +25,6 @@ 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 flush();
|
|
||||||
quint64 bitsAvailable() const
|
quint64 bitsAvailable() const
|
||||||
{return (quint64)_length * 8 + (32 - _used) - _unused;}
|
{return (quint64)_length * 8 + (32 - _used) - _unused;}
|
||||||
|
|
||||||
@ -42,10 +41,19 @@ public:
|
|||||||
: BitStream4(file, hdl, length) {}
|
: BitStream4(file, hdl, length) {}
|
||||||
|
|
||||||
bool read(int bits, quint32 &val);
|
bool read(int bits, quint32 &val);
|
||||||
|
bool flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
class BitStream4R : public BitStream4 {
|
class BitStream4R : public BitStream4 {
|
||||||
public:
|
public:
|
||||||
|
struct State {
|
||||||
|
quint32 pos;
|
||||||
|
quint32 length;
|
||||||
|
quint32 used;
|
||||||
|
quint32 unused;
|
||||||
|
quint32 data;
|
||||||
|
};
|
||||||
|
|
||||||
BitStream4R(const SubFile &file, SubFile::Handle &hdl, quint32 length);
|
BitStream4R(const SubFile &file, SubFile::Handle &hdl, quint32 length);
|
||||||
|
|
||||||
template<typename T> bool read(int bits, T &val);
|
template<typename T> bool read(int bits, T &val);
|
||||||
@ -54,9 +62,42 @@ public:
|
|||||||
bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits);
|
bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits);
|
||||||
|
|
||||||
bool skip(quint32 bytes);
|
bool skip(quint32 bytes);
|
||||||
void resize(quint32 length);
|
void resize(quint32 bytes);
|
||||||
|
void save(State &state);
|
||||||
|
bool restore(const State &state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool BitStream1::read(int bits, T &val)
|
||||||
|
{
|
||||||
|
val = 0;
|
||||||
|
|
||||||
|
for (int pos = 0; pos < bits; ) {
|
||||||
|
if (!_remaining) {
|
||||||
|
if (!_length || !_file.readUInt8(_hdl, _data))
|
||||||
|
return false;
|
||||||
|
_remaining = 8;
|
||||||
|
_length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 get = bits - pos;
|
||||||
|
if (get >= _remaining) {
|
||||||
|
val |= _data << pos;
|
||||||
|
pos += _remaining;
|
||||||
|
_remaining = 0;
|
||||||
|
} else {
|
||||||
|
quint32 mask = (1<<get) - 1;
|
||||||
|
val |= (_data & mask)<<pos;
|
||||||
|
_data >>= get;
|
||||||
|
_remaining -= get;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool BitStream4R::read(int bits, T &val)
|
bool BitStream4R::read(int bits, T &val)
|
||||||
{
|
{
|
||||||
|
@ -28,3 +28,14 @@ bool HuffmanStreamR::init()
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HuffmanStreamR::init(int lonSign, int latSign, quint32 data,
|
||||||
|
quint32 dataSize)
|
||||||
|
{
|
||||||
|
_lonSign = lonSign;
|
||||||
|
_latSign = latSign;
|
||||||
|
_symbolData = data;
|
||||||
|
_symbolDataSize = dataSize;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -11,6 +11,8 @@ public:
|
|||||||
: _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0),
|
: _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0),
|
||||||
_lonSign(0), _latSign(0) {}
|
_lonSign(0), _latSign(0) {}
|
||||||
|
|
||||||
|
bool read(int bits, quint32 &val);
|
||||||
|
bool readSymbol(quint32 &symbol);
|
||||||
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
||||||
{
|
{
|
||||||
if (!(readDelta(_lonSign, lonDelta) && readDelta(_latSign, latDelta)))
|
if (!(readDelta(_lonSign, lonDelta) && readDelta(_latSign, latDelta)))
|
||||||
@ -52,7 +54,31 @@ bool HuffmanStream<BitStream>::sign(int &val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class BitStream>
|
template <class BitStream>
|
||||||
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
bool HuffmanStream<BitStream>::read(int bits, quint32 &val)
|
||||||
|
{
|
||||||
|
if (_symbolDataSize < (quint32)bits) {
|
||||||
|
quint32 next;
|
||||||
|
quint8 nextSize = qMin((quint64)(32 - _symbolDataSize),
|
||||||
|
_bs.bitsAvailable());
|
||||||
|
|
||||||
|
if (!_bs.read(nextSize, next))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_symbolData = (_symbolData << nextSize) | next;
|
||||||
|
_symbolDataSize += nextSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_symbolDataSize < (quint32)bits)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
val = (_symbolData << (32-_symbolDataSize)) >> (32 - bits);
|
||||||
|
_symbolDataSize -= bits;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class BitStream>
|
||||||
|
bool HuffmanStream<BitStream>::readSymbol(quint32 &symbol)
|
||||||
{
|
{
|
||||||
quint8 size;
|
quint8 size;
|
||||||
quint32 next;
|
quint32 next;
|
||||||
@ -65,10 +91,19 @@ bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
|||||||
_symbolDataSize += nextSize;
|
_symbolDataSize += nextSize;
|
||||||
|
|
||||||
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
||||||
|
if (size > _symbolDataSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (size <= _symbolDataSize)
|
|
||||||
_symbolDataSize -= size;
|
_symbolDataSize -= size;
|
||||||
else
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class BitStream>
|
||||||
|
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &delta)
|
||||||
|
{
|
||||||
|
quint32 symbol;
|
||||||
|
if (!readSymbol(symbol))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (symbol && !sign) {
|
if (symbol && !sign) {
|
||||||
@ -79,7 +114,7 @@ bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
|||||||
_symbolDataSize--;
|
_symbolDataSize--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
symbol = sign * symbol;
|
delta = sign * symbol;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -100,6 +135,7 @@ public:
|
|||||||
: HuffmanStream(bitstream, table) {}
|
: HuffmanStream(bitstream, table) {}
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
|
bool init(int lonSign, int latSign, quint32 data, quint32 dataSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HUFFMANSTREAM_H
|
#endif // HUFFMANSTREAM_H
|
||||||
|
@ -2,10 +2,11 @@
|
|||||||
#include "huffmanstream.h"
|
#include "huffmanstream.h"
|
||||||
#include "subdiv.h"
|
#include "subdiv.h"
|
||||||
#include "nodfile.h"
|
#include "nodfile.h"
|
||||||
|
#include "lblfile.h"
|
||||||
#include "netfile.h"
|
#include "netfile.h"
|
||||||
|
|
||||||
|
|
||||||
bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
static bool readAdjCounts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||||
{
|
{
|
||||||
quint32 val, cnt, bits;
|
quint32 val, cnt, bits;
|
||||||
if (!bs.read(4, val))
|
if (!bs.read(4, val))
|
||||||
@ -17,7 +18,6 @@ bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
|||||||
if (cnt == 5) {
|
if (cnt == 5) {
|
||||||
if (!bs.read(8, cnt))
|
if (!bs.read(8, cnt))
|
||||||
return false;
|
return false;
|
||||||
Q_ASSERT(cnt > 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt < 2)
|
if (cnt < 2)
|
||||||
@ -30,14 +30,25 @@ bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
|
static bool skipShape(BitStream4R &bs)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < cnts.size(); i++) {
|
|
||||||
if (cnts.at(i) & mask) {
|
|
||||||
quint32 v1, v2, v2b;
|
quint32 v1, v2, v2b;
|
||||||
|
|
||||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||||
return false;
|
return false;
|
||||||
if (!bs.skip(v1))
|
|
||||||
|
return bs.skip(v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool skipAdjShapes(BitStream4R &bs, const QVector<quint16> &cnts,
|
||||||
|
quint16 mask, bool firstIsShape)
|
||||||
|
{
|
||||||
|
if (firstIsShape && !skipShape(bs))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < cnts.size(); i++) {
|
||||||
|
if (cnts.at(i) & mask) {
|
||||||
|
if (!skipShape(bs))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +56,7 @@ bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool seekToLevel(BitStream4R &bs, quint8 level)
|
static bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||||
{
|
{
|
||||||
quint32 v1, v2, v2b;
|
quint32 v1, v2, v2b;
|
||||||
|
|
||||||
@ -55,7 +66,6 @@ bool seekToLevel(BitStream4R &bs, quint8 level)
|
|||||||
if (!bs.skip(v1))
|
if (!bs.skip(v1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Q_ASSERT(!(v2 & 2));
|
|
||||||
if (v2 & 2)
|
if (v2 & 2)
|
||||||
return false;
|
return false;
|
||||||
if (v2 & 1)
|
if (v2 & 1)
|
||||||
@ -65,7 +75,7 @@ bool seekToLevel(BitStream4R &bs, quint8 level)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool seekToLine(BitStream4R &bs, quint8 line)
|
static bool seekToLine(BitStream4R &bs, quint8 line)
|
||||||
{
|
{
|
||||||
quint32 v1, v2, v2b;
|
quint32 v1, v2, v2b;
|
||||||
|
|
||||||
@ -75,7 +85,6 @@ bool seekToLine(BitStream4R &bs, quint8 line)
|
|||||||
if (!bs.skip(v1))
|
if (!bs.skip(v1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Q_ASSERT(!(v2 & 2));
|
|
||||||
if (v2 & 2)
|
if (v2 & 2)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -83,87 +92,9 @@ bool seekToLine(BitStream4R &bs, quint8 line)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool readLine(BitStream4R &bs, const SubDiv *subdiv,
|
||||||
bool NETFile::init(Handle &hdl)
|
const HuffmanTable &table, IMG::Poly &poly)
|
||||||
{
|
{
|
||||||
quint8 multiplier;
|
|
||||||
quint16 hdrLen;
|
|
||||||
|
|
||||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
|
||||||
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
|
||||||
&& 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<<multiplier;
|
|
||||||
|
|
||||||
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;
|
quint32 v1, v2, v2b;
|
||||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||||
return false;
|
return false;
|
||||||
@ -175,18 +106,13 @@ bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
|
|||||||
if (2 < v2b)
|
if (2 < v2b)
|
||||||
lon |= (v2 >> 2) << (0x12U - v2b);
|
lon |= (v2 >> 2) << (0x12U - v2b);
|
||||||
|
|
||||||
QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon,
|
QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon, 32-subdiv->bits()),
|
||||||
32-subdiv->bits()), LS(subdiv->lat(), 8) + LS((qint16)lat,
|
LS(subdiv->lat(), 8) + LS((qint16)lat, 32-subdiv->bits()));
|
||||||
32-subdiv->bits()));
|
|
||||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
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.boundingRect = RectC(c, c);
|
||||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
|
||||||
Q_ASSERT(_tableId == table.id());
|
|
||||||
HuffmanStreamR stream(bs, table);
|
HuffmanStreamR stream(bs, table);
|
||||||
if (!stream.init())
|
if (!stream.init())
|
||||||
return false;
|
return false;
|
||||||
@ -203,18 +129,380 @@ bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
|
|||||||
poly.boundingRect = poly.boundingRect.united(c);
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
lines->append(poly);
|
return stream.atEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool readNodeGeometry(NODFile *nod, SubFile::Handle &nodHdl,
|
||||||
|
NODFile::AdjacencyInfo &adj, IMG::Poly &poly, quint16 cnt = 0xFFFF)
|
||||||
|
{
|
||||||
|
for (int i = 0; i <= cnt; i++) {
|
||||||
|
int ret = nod->nextNode(nodHdl, adj);
|
||||||
|
if (ret < 0)
|
||||||
|
return false;
|
||||||
|
else if (ret > 0)
|
||||||
|
return (cnt == 0xFFFF);
|
||||||
|
|
||||||
|
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||||
|
toWGS32(adj.nodeInfo.pos.y()));
|
||||||
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool skipNodes(NODFile *nod, SubFile::Handle &nodHdl,
|
||||||
|
NODFile::AdjacencyInfo &adj, int cnt)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cnt; i++)
|
||||||
|
if (nod->nextNode(nodHdl, adj))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool readShape(NODFile *nod, SubFile::Handle &nodHdl,
|
||||||
|
NODFile::AdjacencyInfo &adj, BitStream4R &bs, const HuffmanTable &table,
|
||||||
|
const SubDiv *subdiv, quint32 shift, IMG::Poly &poly, quint16 cnt = 0xFFFF,
|
||||||
|
bool check = false)
|
||||||
|
{
|
||||||
|
quint32 v1, v2, v2b;
|
||||||
|
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||||
|
return false;
|
||||||
|
BitStream4R::State state;
|
||||||
|
bs.save(state);
|
||||||
|
bs.resize(v1);
|
||||||
|
|
||||||
|
quint32 flags;
|
||||||
|
if (!bs.read(8, flags))
|
||||||
|
return false;
|
||||||
|
flags |= (v2 << 8);
|
||||||
|
|
||||||
|
bool hasCoordinatesAdjustBit = flags & (1 << (v2b + 7));
|
||||||
|
bool useEosBit = flags & (1 << (v2b + 5));
|
||||||
|
bool startWithStream = flags & (1 << (v2b + 6));
|
||||||
|
|
||||||
|
quint32 extraBits;
|
||||||
|
int lonSign, latSign;
|
||||||
|
|
||||||
|
if ((flags >> (v2b + 4) & 1) == 0) {
|
||||||
|
extraBits = v2b + 4;
|
||||||
|
lonSign = 0;
|
||||||
|
} else {
|
||||||
|
extraBits = v2b + 3;
|
||||||
|
lonSign = 1;
|
||||||
|
if ((flags >> (v2b + 3) & 1) != 0) {
|
||||||
|
lonSign = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extraBits -= 1;
|
||||||
|
if ((flags >> extraBits & 1) == 0) {
|
||||||
|
latSign = 0;
|
||||||
|
} else {
|
||||||
|
extraBits -= 1;
|
||||||
|
latSign = -1;
|
||||||
|
if ((flags >> extraBits & 1) == 0) {
|
||||||
|
latSign = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nod->nextNode(nodHdl, adj))
|
||||||
|
return false;
|
||||||
|
QPoint pos(adj.nodeInfo.pos);
|
||||||
|
quint16 nodes = 0;
|
||||||
|
|
||||||
|
if (!startWithStream) {
|
||||||
|
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||||
|
toWGS32(adj.nodeInfo.pos.y()));
|
||||||
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
|
|
||||||
|
while (!(adj.flags & 1)) {
|
||||||
|
int ret = nod->nextNode(nodHdl, adj);
|
||||||
|
if (ret < 0)
|
||||||
|
return false;
|
||||||
|
else if (ret > 0)
|
||||||
|
break;
|
||||||
|
nodes++;
|
||||||
|
|
||||||
|
c = Coordinates(toWGS32(adj.nodeInfo.pos.x()),
|
||||||
|
toWGS32(adj.nodeInfo.pos.y()));
|
||||||
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
|
pos = adj.nodeInfo.pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HuffmanStreamR stream(bs, table);
|
||||||
|
if (!stream.init(lonSign, latSign, flags, extraBits))
|
||||||
|
return false;
|
||||||
|
qint32 lonDelta, latDelta;
|
||||||
|
QVector<QPoint> deltas;
|
||||||
|
|
||||||
|
quint32 adjustBit = 0;
|
||||||
|
quint32 stepsCnt = 0;
|
||||||
|
quint32 steps = 0;
|
||||||
|
quint32 eos = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if ((stepsCnt == steps) && !useEosBit) {
|
||||||
|
if (!stream.readSymbol(steps))
|
||||||
|
break;
|
||||||
|
if (!steps)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stream.readNext(lonDelta, latDelta))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (hasCoordinatesAdjustBit && !stream.read(1, adjustBit))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
stepsCnt++;
|
||||||
|
|
||||||
|
if (useEosBit) {
|
||||||
|
if (!stream.read(1, eos))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (steps == stepsCnt)
|
||||||
|
eos = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!startWithStream) {
|
||||||
|
pos.rx() += LS(lonDelta, 32-subdiv->bits()-shift);
|
||||||
|
pos.ry() += LS(latDelta, 32-subdiv->bits()-shift);
|
||||||
|
|
||||||
|
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||||
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
|
} else {
|
||||||
|
deltas.append(QPoint(lonDelta, latDelta));
|
||||||
|
poly.points.append(QPointF());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startWithStream && eos) {
|
||||||
|
for (int i = deltas.size() - 1, j = 0; i >= 0; i--, j++) {
|
||||||
|
pos.rx() -= LS(deltas.at(i).x(), 32-subdiv->bits()-shift);
|
||||||
|
pos.ry() -= LS(deltas.at(i).y(), 32-subdiv->bits()-shift);
|
||||||
|
|
||||||
|
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||||
|
poly.points[poly.points.size() - 1 - j] = QPointF(c.lon(), c.lat());
|
||||||
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = adj.nodeInfo.pos;
|
||||||
|
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||||
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
|
|
||||||
|
stepsCnt = 0;
|
||||||
|
steps = 0;
|
||||||
|
startWithStream = false;
|
||||||
|
|
||||||
|
if (adj.flags & 1)
|
||||||
|
eos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eos) {
|
||||||
|
if (nodes >= cnt)
|
||||||
|
break;
|
||||||
|
|
||||||
|
do {
|
||||||
|
int ret = nod->nextNode(nodHdl, adj);
|
||||||
|
if (ret < 0)
|
||||||
|
return false;
|
||||||
|
else if (ret > 0)
|
||||||
|
break;
|
||||||
|
nodes++;
|
||||||
|
|
||||||
|
if (check && nodes == cnt) {
|
||||||
|
if (!(bs.restore(state) && bs.skip(v1)
|
||||||
|
&& bs.readVuint32SM(v1, v2, v2b)))
|
||||||
|
return false;
|
||||||
|
if (5 < v2b)
|
||||||
|
v2 >>= v2b - 2;
|
||||||
|
if (v2 & 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||||
|
toWGS32(adj.nodeInfo.pos.y()));
|
||||||
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
|
pos = adj.nodeInfo.pos;
|
||||||
|
} while (!(adj.flags & 1) && nodes < cnt);
|
||||||
|
|
||||||
|
if (nodes == cnt)
|
||||||
|
break;
|
||||||
|
|
||||||
|
steps = 0;
|
||||||
|
stepsCnt = 0;
|
||||||
|
eos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NETFile::linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
|
||||||
|
Handle &lblHdl, Label &label)
|
||||||
|
{
|
||||||
|
if (!seek(hdl, offset))
|
||||||
|
return false;
|
||||||
|
BitStream1 bs(*this, hdl, size);
|
||||||
|
|
||||||
|
quint32 flags, b, labelPtr = 0;
|
||||||
|
if (!bs.read(8, flags))
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (!bs.read(8, b))
|
||||||
|
return false;
|
||||||
|
labelPtr |= (b << (i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lbl && (labelPtr & 0x3FFFFF)) {
|
||||||
|
if (labelPtr & 0x400000) {
|
||||||
|
quint32 lblOff;
|
||||||
|
if (lblOffset(hdl, labelPtr & 0x3FFFFF, lblOff) && lblOff)
|
||||||
|
label = lbl->label(lblHdl, lblOff);
|
||||||
|
|
||||||
|
} else
|
||||||
|
label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NETFile::init(Handle &hdl)
|
||||||
|
{
|
||||||
|
quint16 hdrLen;
|
||||||
|
|
||||||
|
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
||||||
|
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
||||||
|
&& readUInt32(hdl, _size) && readUInt8(hdl, _shift)))
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
_init = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||||
|
NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
|
||||||
|
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
|
||||||
|
const HuffmanTable &table, QList<IMG::Poly> *lines)
|
||||||
|
{
|
||||||
|
if (!_init && !init(hdl))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Q_ASSERT(_tableId == table.id());
|
||||||
|
if (_tableId != table.id())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IMG::Poly poly;
|
||||||
|
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NODFile::LinkInfo linkInfo;
|
||||||
|
if (!nod->linkInfo(nodHdl, blockInfo, linkId, linkInfo))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
quint32 linkOffset = _linksOffset + (linkInfo.linkOffset << _linksShift);
|
||||||
|
if (linkOffset > _linksOffset + _linksSize)
|
||||||
|
return false;
|
||||||
|
if (!seek(hdl, linkOffset))
|
||||||
|
return false;
|
||||||
|
BitStream4R bs(*this, hdl, linkOffset - _linksOffset);
|
||||||
|
QVector<quint16> ca;
|
||||||
|
quint16 mask = 0;
|
||||||
|
quint32 size;
|
||||||
|
|
||||||
|
quint8 s68 = (linkInfo.flags >> 0x12) & 1;
|
||||||
|
quint8 s69 = (linkInfo.flags >> 0x11) & 1;
|
||||||
|
quint8 s6a = (linkInfo.flags >> 0x13) & 1;
|
||||||
|
|
||||||
|
if (s69 == 0 || s6a == 1) {
|
||||||
|
if (!bs.readVUInt32(size))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (s69 == 0) {
|
||||||
|
if (!readAdjCounts(bs, ca, mask))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!subdiv->level()) {
|
||||||
|
NODFile::AdjacencyInfo adj(nod, blockInfo, linkId, linkInfo);
|
||||||
|
|
||||||
|
if (s69 == 1) {
|
||||||
|
if (s68 == 1) {
|
||||||
|
if (!readShape(nod, nodHdl, adj, bs, table, subdiv, shift, poly))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (!readNodeGeometry(nod, nodHdl, adj, poly))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quint16 mask2 = mask + 0xffff;
|
||||||
|
for (int i = 0; i <= ca.size(); i++) {
|
||||||
|
quint16 step = (i < ca.size()) ? ca.at(i) & mask2 : 0xFFFF;
|
||||||
|
bool shape = (i > 0) ? ca.at(i-1) & mask : (s68 == 1);
|
||||||
|
if (i == lineId) {
|
||||||
|
if (shape) {
|
||||||
|
bool check = (i < ca.size()) ? (ca.at(i) & mask) : false;
|
||||||
|
if (!readShape(nod, nodHdl, adj, bs, table, subdiv,
|
||||||
|
shift, poly, step, check))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (!readNodeGeometry(nod, nodHdl, adj, poly, step))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shape && !skipShape(bs))
|
||||||
|
return false;
|
||||||
|
if (!skipNodes(nod, nodHdl, adj, step))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!skipAdjShapes(bs, ca, mask, s68 == 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!seekToLevel(bs, subdiv->level()))
|
||||||
|
return false;
|
||||||
|
if (!seekToLine(bs, lineId))
|
||||||
|
return false;
|
||||||
|
if (!readLine(bs, subdiv, table, poly))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkLabel(hdl, linkOffset, _linksSize - (linkOffset - _linksOffset), lbl,
|
||||||
|
lblHdl, poly.label);
|
||||||
|
|
||||||
|
lines->append(poly);
|
||||||
|
|
||||||
return true;
|
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 (!_init && !init(hdl))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!(seek(hdl, _offset + netOffset * _multiplier)
|
if (!(seek(hdl, _offset + (netOffset << _shift))
|
||||||
&& readUInt24(hdl, lblOffset)))
|
&& readUInt24(hdl, lblOffset)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -14,24 +14,29 @@ class NETFile : public SubFile
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0),
|
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0),
|
||||||
_linksSize(0), _multiplier(0), _linksShift(0) {}
|
_linksSize(0), _shift(0), _linksShift(0), _init(false) {}
|
||||||
NETFile(const QString &path) : SubFile(path), _offset(0), _size(0),
|
NETFile(const QString &path) : SubFile(path), _offset(0), _size(0),
|
||||||
_linksOffset(0), _linksSize(0), _multiplier(0), _linksShift(0) {}
|
_linksOffset(0), _linksSize(0), _shift(0), _linksShift(0),
|
||||||
|
_init(false) {}
|
||||||
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||||
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _multiplier(0),
|
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _shift(0),
|
||||||
_linksShift(0) {}
|
_linksShift(0), _init(false) {}
|
||||||
|
|
||||||
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,
|
bool link(const SubDiv *subdiv, quint32 shift, Handle &hdl, NODFile *nod,
|
||||||
|
Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
|
||||||
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
|
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
|
||||||
const HuffmanTable &table, QList<IMG::Poly> *lines);
|
const HuffmanTable &table, QList<IMG::Poly> *lines);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool init(Handle &hdl);
|
bool init(Handle &hdl);
|
||||||
|
bool linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
|
||||||
|
Handle &lblHdl, Label &label);
|
||||||
|
|
||||||
quint32 _offset, _size, _linksOffset, _linksSize;
|
quint32 _offset, _size, _linksOffset, _linksSize;
|
||||||
quint8 _multiplier, _linksShift;
|
quint8 _shift, _linksShift;
|
||||||
quint8 _tableId;
|
quint8 _tableId;
|
||||||
|
bool _init;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NETFILE_H
|
#endif // NETFILE_H
|
||||||
|
@ -1,6 +1,81 @@
|
|||||||
#include "bitstream.h"
|
#include "bitstream.h"
|
||||||
#include "nodfile.h"
|
#include "nodfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(array) \
|
||||||
|
(sizeof(array) / sizeof(array[0]))
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
quint8 lon;
|
||||||
|
quint8 lat;
|
||||||
|
} LLBITS[] = {
|
||||||
|
{0xc, 0xc}, {0x8, 0x10}, {0x10, 0x8}, {0x10, 0x10}, {0xc, 0x14},
|
||||||
|
{0x14, 0xc}, {0x14, 0x14}
|
||||||
|
};
|
||||||
|
|
||||||
|
union NodeShift {
|
||||||
|
qint32 offset;
|
||||||
|
quint8 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool adjDistInfo(BitStream1 &bs, bool extraBit, quint8 &flags)
|
||||||
|
{
|
||||||
|
quint32 data, cnt;
|
||||||
|
|
||||||
|
if (!bs.read(extraBit | 8, data))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data <<= !extraBit;
|
||||||
|
flags |= (quint8)data & 1;
|
||||||
|
data >>= 1;
|
||||||
|
|
||||||
|
for (cnt = 0; (data >> cnt) & 1; cnt++) {
|
||||||
|
if (cnt == 4)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!bs.read(cnt * 4, data))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool adjNodeInfo(BitStream1 &bs, bool extraBit, NodeShift &shift,
|
||||||
|
quint8 &flags)
|
||||||
|
{
|
||||||
|
quint32 data;
|
||||||
|
|
||||||
|
if (!bs.read(9, data))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data <<= !extraBit;
|
||||||
|
|
||||||
|
if (data & 1)
|
||||||
|
shift.id = data >> 1;
|
||||||
|
else {
|
||||||
|
quint32 bits = (data >> 1) & 7;
|
||||||
|
quint32 data2;
|
||||||
|
flags |= 2;
|
||||||
|
|
||||||
|
if (!bs.read(bits + extraBit + 1, data2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data = data2 << (6 - extraBit) | data >> 4;
|
||||||
|
bits = 0x19 - bits;
|
||||||
|
shift.offset = ((qint32)(data << bits) >> bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool skipOptAdjData(BitStream1 &bs)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
Q_UNUSED(bs);
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool NODFile::init(Handle &hdl)
|
bool NODFile::init(Handle &hdl)
|
||||||
{
|
{
|
||||||
quint16 hdrLen;
|
quint16 hdrLen;
|
||||||
@ -9,9 +84,10 @@ bool NODFile::init(Handle &hdl)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (hdrLen >= 0x7b) {
|
if (hdrLen >= 0x7b) {
|
||||||
if (!(seek(hdl, _gmpOffset + 0x21) && readUInt8(hdl, _blockShift)
|
if (!(seek(hdl, _gmpOffset + 0x1d) && readUInt32(hdl, _flags)
|
||||||
&& readUInt8(hdl, _nodeShift)))
|
&& readUInt8(hdl, _blockShift) && readUInt8(hdl, _nodeShift)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!(seek(hdl, _gmpOffset + 0x67) && readUInt32(hdl, _blockOffset)
|
if (!(seek(hdl, _gmpOffset + 0x67) && readUInt32(hdl, _blockOffset)
|
||||||
&& readUInt32(hdl, _blockSize) && readUInt16(hdl, _blockRecordSize)
|
&& readUInt32(hdl, _blockSize) && readUInt16(hdl, _blockRecordSize)
|
||||||
&& readUInt32(hdl, _indexOffset) && readUInt32(hdl, _indexSize)
|
&& readUInt32(hdl, _indexOffset) && readUInt32(hdl, _indexSize)
|
||||||
@ -38,42 +114,49 @@ quint32 NODFile::indexIdSize(Handle &hdl)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NODFile::blockInfo(Handle &hdl, quint32 blockIndexId,
|
bool NODFile::readBlock(Handle &hdl, quint32 blockOffset,
|
||||||
BlockInfo &blockInfo) const
|
BlockInfo &blockInfo) const
|
||||||
{
|
{
|
||||||
quint32 blockOffset;
|
blockInfo.offset = blockOffset;
|
||||||
quint32 offset = _indexRecordSize * blockIndexId + _indexOffset;
|
|
||||||
quint32 offsetSize = (_indexFlags & 3) + 1;
|
|
||||||
|
|
||||||
|
if (!(seek(hdl, blockInfo.offset + _blockOffset)
|
||||||
Q_ASSERT(offset <= _indexOffset + _indexSize);
|
&& readUInt16(hdl, blockInfo.hdr.s0) && readUInt32(hdl, blockInfo.hdr.s2)
|
||||||
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
|
&& readUInt32(hdl, blockInfo.hdr.s6) && readUInt32(hdl, blockInfo.hdr.sa)
|
||||||
return false;
|
&& readUInt16(hdl, blockInfo.hdr.se) && readUInt8(hdl, blockInfo.hdr.s10)
|
||||||
|
&& readUInt8(hdl, blockInfo.hdr.s11) && readUInt8(hdl, blockInfo.hdr.s12)))
|
||||||
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 false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NODFile::blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const
|
||||||
|
{
|
||||||
|
quint32 blockOffset;
|
||||||
|
quint32 offset = _indexRecordSize * blockId + _indexOffset;
|
||||||
|
quint32 offsetSize = (_indexFlags & 3) + 1;
|
||||||
|
|
||||||
|
if (offset > _indexOffset + _indexSize)
|
||||||
|
return false;
|
||||||
|
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return readBlock(hdl, blockOffset << _blockShift, blockInfo);
|
||||||
|
}
|
||||||
|
|
||||||
bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
||||||
LinkInfo &linkInfo) const
|
LinkInfo &linkInfo) const
|
||||||
{
|
{
|
||||||
Q_ASSERT(linkId < blockInfo.h10);
|
if (linkId >= blockInfo.hdr.s10)
|
||||||
|
return false;
|
||||||
|
|
||||||
quint32 infoOffset = ((blockInfo.he * linkId) >> 3) + 0x13
|
quint32 infoOffset = ((blockInfo.hdr.se * linkId) >> 3) + 0x13
|
||||||
+ ((blockInfo.h0 >> 0xb) & 1) + blockInfo.offset;
|
+ ((blockInfo.hdr.s0 >> 0xb) & 1) + blockInfo.offset + _blockOffset;
|
||||||
quint32 s1 = ((blockInfo.h0 >> 2) & 0x1f) + 8;
|
quint32 s1 = ((blockInfo.hdr.s0 >> 2) & 0x1f) + 8;
|
||||||
quint32 s2 = (blockInfo.h0 >> 7) & 0xf;
|
quint32 s2 = (blockInfo.hdr.s0 >> 7) & 0xf;
|
||||||
quint32 skip = (blockInfo.he * linkId) & 7;
|
quint32 skip = (blockInfo.hdr.se * linkId) & 7;
|
||||||
|
|
||||||
Q_ASSERT(infoOffset <= _blockOffset + _blockSize);
|
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
|
||||||
|
return false;
|
||||||
if (!seek(hdl, infoOffset))
|
if (!seek(hdl, infoOffset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -90,20 +173,340 @@ bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
|||||||
} else {
|
} else {
|
||||||
if (!bs.read(s1 - s2, linkInfo.linkOffset))
|
if (!bs.read(s1 - s2, linkInfo.linkOffset))
|
||||||
return false;
|
return false;
|
||||||
linkInfo.linkOffset += blockInfo.ha;
|
linkInfo.linkOffset += blockInfo.hdr.sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!bs.read(s2, linkInfo.nodeOffset))
|
||||||
|
return false;
|
||||||
|
linkInfo.nodeOffset = (blockInfo.offset - linkInfo.nodeOffset)
|
||||||
|
>> _nodeShift;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NODFile::nodeInfo(Handle &hdl, const BlockInfo &blockInfo,
|
||||||
|
quint32 nodeOffset, NodeInfo &nodeInfo) const
|
||||||
|
{
|
||||||
|
quint32 infoOffset = (nodeOffset << _nodeShift) + _blockOffset;
|
||||||
|
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
|
||||||
|
return false;
|
||||||
|
if (!seek(hdl, infoOffset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||||
|
|
||||||
|
if (!bs.read(8, nodeInfo.flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((nodeInfo.flags & 7) >= ARRAY_SIZE(LLBITS))
|
||||||
|
return false;
|
||||||
|
quint8 lonBits = LLBITS[nodeInfo.flags & 7].lon;
|
||||||
|
quint8 latBits = LLBITS[nodeInfo.flags & 7].lat;
|
||||||
|
quint8 maxBits = ((_flags >> 10) & 7) | 0x18;
|
||||||
|
|
||||||
|
quint32 lon, lat;
|
||||||
|
if (!(bs.read(lonBits, lon) && bs.read(latBits, lat)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
quint8 lonShift = 0x20 - lonBits;
|
||||||
|
quint8 latShift = 0x20 - latBits;
|
||||||
|
quint8 shift = 0x20 - maxBits;
|
||||||
|
QPoint pos((((int)(lon << lonShift) >> lonShift) << shift)
|
||||||
|
+ blockInfo.hdr.s2, (((int)(lat << latShift) >> latShift) << shift)
|
||||||
|
+ blockInfo.hdr.s6);
|
||||||
|
nodeInfo.bytes = ((lonBits + latBits) >> 3) + 1;
|
||||||
|
|
||||||
|
if ((maxBits < 0x1c) && (nodeInfo.flags & 8)) {
|
||||||
|
quint8 extraBits = 0x1c - maxBits;
|
||||||
|
quint32 extraLon, extraLat;
|
||||||
|
|
||||||
|
if (!(bs.read(extraBits, extraLon) && bs.read(extraBits, extraLat)))
|
||||||
|
return false;
|
||||||
|
pos.setX(pos.x() | extraLon << 4); pos.setY(pos.y() | extraLat << 4);
|
||||||
|
nodeInfo.bytes++;
|
||||||
|
}
|
||||||
|
// TODO?: extra bits
|
||||||
|
|
||||||
|
nodeInfo.pos = pos;
|
||||||
|
nodeInfo.flags &= 0xf8;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NODFile::nodeOffset(Handle &hdl, const BlockInfo &blockInfo,
|
||||||
|
quint8 nodeId, quint32 &nodeOffset) const
|
||||||
|
{
|
||||||
|
if (nodeId >= blockInfo.hdr.s11)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
quint32 offset = ((blockInfo.hdr.s10 * blockInfo.hdr.se + 7) >> 3)
|
||||||
|
+ 0x13 + nodeId * 3 + _blockOffset + blockInfo.offset
|
||||||
|
+ ((blockInfo.hdr.s0 >> 0xb) & 1);
|
||||||
|
|
||||||
|
if (!(seek(hdl, offset) && readUInt24(hdl, nodeOffset)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NODFile::nodeBlock(Handle &hdl, quint32 nodeOffset,
|
||||||
|
BlockInfo &blockInfo) const
|
||||||
|
{
|
||||||
|
int low = 0;
|
||||||
|
int high = _indexSize / _indexRecordSize - 1;
|
||||||
|
quint32 offsetSize = (_indexFlags & 3) + 1;
|
||||||
|
|
||||||
|
while (low <= high) {
|
||||||
|
quint32 m = ((low + high) / 2);
|
||||||
|
quint32 offset = _indexRecordSize * m + _indexOffset;
|
||||||
|
quint32 blockOffset, prevBlockOffset;
|
||||||
|
|
||||||
|
if (m > 0) {
|
||||||
|
if (!(seek(hdl, offset - _indexRecordSize)
|
||||||
|
&& readVUInt32(hdl, offsetSize, prevBlockOffset)
|
||||||
|
&& readVUInt32(hdl, offsetSize, blockOffset)))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (!(seek(hdl, offset)
|
||||||
|
&& readVUInt32(hdl, offsetSize, blockOffset)))
|
||||||
|
return false;
|
||||||
|
prevBlockOffset = 0;
|
||||||
|
}
|
||||||
|
prevBlockOffset <<= _blockShift;
|
||||||
|
blockOffset <<= _blockShift;
|
||||||
|
|
||||||
|
if (blockOffset < nodeOffset)
|
||||||
|
low = m + 1;
|
||||||
|
else {
|
||||||
|
if (prevBlockOffset <= nodeOffset)
|
||||||
|
return readBlock(hdl, blockOffset, blockInfo);
|
||||||
|
else
|
||||||
|
high = m - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NODFile::absAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||||
|
{
|
||||||
|
quint32 infoOffset = (adj.nodeOffset << _nodeShift) + _blockOffset
|
||||||
|
+ adj.nodeInfo.bytes;
|
||||||
|
if (!seek(hdl, infoOffset))
|
||||||
|
return false;
|
||||||
|
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||||
|
|
||||||
|
quint8 linkId = adj.blockInfo.hdr.s10;
|
||||||
|
quint32 m2p = 2;
|
||||||
|
quint32 skip = 8;
|
||||||
|
quint32 flags;
|
||||||
|
quint32 nextOffset;
|
||||||
|
bool extraBit = (adj.nodeInfo.flags >> 6) & 1;
|
||||||
|
bool linkIdValid = true;
|
||||||
|
bool firstLoop = true;
|
||||||
|
|
||||||
|
do {
|
||||||
|
adj.flags = 0;
|
||||||
|
|
||||||
|
if (!bs.read(8, flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (firstLoop) {
|
||||||
|
skip >>= (flags >> 5) & 1;
|
||||||
|
flags |= 0x20;
|
||||||
|
}
|
||||||
|
firstLoop = false;
|
||||||
|
quint32 f4 = flags & 0x10;
|
||||||
|
quint32 f4sn = (f4 >> 4) ^ 1;
|
||||||
|
quint32 m1 = (flags >> 5) & f4sn;
|
||||||
|
quint32 m2 = (f4 >> 3) | (f4sn & (flags >> 6));
|
||||||
|
|
||||||
|
if (m1) {
|
||||||
|
if (!bs.read(8, linkId))
|
||||||
|
return false;
|
||||||
|
linkIdValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m2 != m2p) || (flags & 0x10) || m1) {
|
||||||
|
quint32 data;
|
||||||
|
if (!bs.read(skip, data))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & 0x10)) {
|
||||||
|
if (!adjDistInfo(bs, (m2 == 1 && linkIdValid), adj.flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NodeShift shift;
|
||||||
|
if (!adjNodeInfo(bs, extraBit, shift, adj.flags))
|
||||||
|
return false;
|
||||||
|
if (adj.flags & 2)
|
||||||
|
nextOffset = adj.nodeOffset + shift.offset;
|
||||||
|
else if (!nodeOffset(adj.extHdl, adj.blockInfo, shift.id, nextOffset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m2p = m2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & 0x8) {
|
||||||
|
quint32 data;
|
||||||
|
if (!bs.read(8, data))
|
||||||
|
return false;
|
||||||
|
if (!(data & 0xe0)) {
|
||||||
|
if (!bs.read(8, data))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_flags & 0x18) && !skipOptAdjData(bs))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((m2 == 1) && linkIdValid) {
|
||||||
|
LinkInfo li;
|
||||||
|
if (adj.linkId == 0xFFFFFFFF) {
|
||||||
|
if (!linkInfo(adj.extHdl, adj.blockInfo, linkId, li))
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
li.linkOffset = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
if ((adj.linkOffset == li.linkOffset) || (adj.linkId == linkId)) {
|
||||||
|
adj.nodeOffset = nextOffset;
|
||||||
|
if (!(adj.flags & 2)) {
|
||||||
|
adj.linkId = 0xFFFFFFFF;
|
||||||
|
return nodeBlock(hdl, adj.nodeOffset << _nodeShift,
|
||||||
|
adj.blockInfo);
|
||||||
|
} else {
|
||||||
|
adj.linkId = linkId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linkIdValid = false;
|
||||||
|
}
|
||||||
|
} while (!(flags & 0x80));
|
||||||
|
|
||||||
|
adj.nodeOffset = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NODFile::relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||||
|
{
|
||||||
|
quint32 infoOffset = (adj.nodeOffset << _nodeShift) + _blockOffset
|
||||||
|
+ adj.nodeInfo.bytes;
|
||||||
|
if (!seek(hdl, infoOffset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||||
|
|
||||||
|
quint32 linkId = adj.blockInfo.hdr.s10;
|
||||||
|
quint32 skip = 8;
|
||||||
|
quint32 flagsBits = 8;
|
||||||
|
quint32 flags;
|
||||||
|
quint32 nextOffset;
|
||||||
|
bool extraBit = (adj.nodeInfo.flags >> 6) & 1;
|
||||||
|
bool linkIdValid = true;
|
||||||
|
bool firstLoop = true;
|
||||||
|
|
||||||
|
do {
|
||||||
|
adj.flags = 0;
|
||||||
|
|
||||||
|
if (!bs.read(flagsBits, flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
flags <<= (8U - flagsBits);
|
||||||
|
if (firstLoop) {
|
||||||
|
skip >>= (flags >> 5) & 1;
|
||||||
|
flags = ((flags >> 1) & 0x20) | (flags & 0xffffffdf);
|
||||||
|
}
|
||||||
|
firstLoop = false;
|
||||||
|
flagsBits >>= (flags >> 3) & 1;
|
||||||
|
quint32 m = (((flags & 0x70) == 0x30) << 1) | ((flags >> 6) & 1);
|
||||||
|
if (!m) {
|
||||||
|
adj.nodeOffset = 0xFFFFFFFF;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & 0x60) == 0x60) {
|
||||||
|
if (!bs.read(8, linkId))
|
||||||
|
return false;
|
||||||
|
linkIdValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((flags & 0x70) == 0x70)) {
|
||||||
|
quint32 data;
|
||||||
|
if (!bs.read(skip, data))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & 0x50) == 0x50) {
|
||||||
|
if (!adjDistInfo(bs, false, adj.flags))
|
||||||
|
return false;
|
||||||
|
adj.flags |= 1;
|
||||||
|
}
|
||||||
|
if ((flags >> 6) & 1) {
|
||||||
|
NodeShift shift;
|
||||||
|
if (!adjNodeInfo(bs, extraBit, shift, adj.flags))
|
||||||
|
return false;
|
||||||
|
if (adj.flags & 2)
|
||||||
|
nextOffset = adj.nodeOffset + shift.offset;
|
||||||
|
else if (!nodeOffset(adj.extHdl, adj.blockInfo, shift.id, nextOffset))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_flags & 0x18) && !skipOptAdjData(bs))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (((m == 1) && linkIdValid)) {
|
||||||
|
LinkInfo li;
|
||||||
|
if (adj.linkId == 0xFFFFFFFF) {
|
||||||
|
if (!linkInfo(adj.extHdl, adj.blockInfo, linkId, li))
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
li.linkOffset = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
if ((adj.linkOffset == li.linkOffset) || (adj.linkId == linkId)) {
|
||||||
|
adj.nodeOffset = nextOffset;
|
||||||
|
if (!(adj.flags & 2)) {
|
||||||
|
adj.linkId = 0xFFFFFFFF;
|
||||||
|
return nodeBlock(hdl, adj.nodeOffset << _nodeShift,
|
||||||
|
adj.blockInfo);
|
||||||
|
} else {
|
||||||
|
adj.linkId = linkId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
linkIdValid = false;
|
||||||
|
}
|
||||||
|
} while (!(flags & 0x80));
|
||||||
|
|
||||||
|
adj.nodeOffset = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NODFile::nextNode(Handle &hdl, AdjacencyInfo &adjInfo)
|
||||||
|
{
|
||||||
|
if (adjInfo.nodeOffset == 0xFFFFFFFF)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!nodeInfo(hdl, adjInfo.blockInfo, adjInfo.nodeOffset,
|
||||||
|
adjInfo.nodeInfo))
|
||||||
|
return -1;
|
||||||
|
if (!adjacencyInfo(hdl, adjInfo))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
||||||
quint32 &type) const
|
quint32 &type) const
|
||||||
{
|
{
|
||||||
quint32 offset = ((blockInfo.h10 * blockInfo.he + 7) >> 3) + 0x13 +
|
quint32 offset = ((blockInfo.hdr.s10 * blockInfo.hdr.se + 7) >> 3) + 0x13
|
||||||
blockInfo.offset + ((blockInfo.h0 >> 0xb) & 1) + (quint32)blockInfo.h11
|
+ blockInfo.offset + _blockOffset + ((blockInfo.hdr.s0 >> 0xb) & 1)
|
||||||
* 3;
|
+ blockInfo.hdr.s11 * 3;
|
||||||
quint32 low = 0;
|
quint32 low = 0;
|
||||||
quint32 high = blockInfo.h12 - 1;
|
quint32 high = blockInfo.hdr.s12 - 1;
|
||||||
quint32 pos;
|
quint32 pos;
|
||||||
quint16 val;
|
quint16 val;
|
||||||
|
|
||||||
@ -142,7 +545,7 @@ bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type *= 256;
|
type <<= 8;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -7,23 +7,53 @@
|
|||||||
class NODFile : public SubFile
|
class NODFile : public SubFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct BlockInfo {
|
struct BlockInfo
|
||||||
|
{
|
||||||
quint32 offset;
|
quint32 offset;
|
||||||
quint16 h0;
|
struct
|
||||||
quint32 h2;
|
{
|
||||||
quint32 h6;
|
quint32 s2; // node lon base
|
||||||
quint32 ha;
|
quint32 s6; // node lat base
|
||||||
quint16 he;
|
quint32 sa;
|
||||||
quint8 h10; // links count
|
quint16 s0; // flags
|
||||||
quint8 h11;
|
quint16 se; // link info bit size
|
||||||
quint8 h12;
|
quint8 s10; // links count
|
||||||
|
quint8 s11; // nodes count
|
||||||
|
quint8 s12; // link types count
|
||||||
|
} hdr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LinkInfo {
|
struct LinkInfo
|
||||||
|
{
|
||||||
quint32 linkOffset;
|
quint32 linkOffset;
|
||||||
|
quint32 nodeOffset;
|
||||||
quint32 flags;
|
quint32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NodeInfo
|
||||||
|
{
|
||||||
|
QPoint pos;
|
||||||
|
quint8 flags;
|
||||||
|
quint8 bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AdjacencyInfo
|
||||||
|
{
|
||||||
|
AdjacencyInfo(const SubFile *file, const BlockInfo &blockInfo,
|
||||||
|
quint32 linkId, const LinkInfo &linkInfo) : extHdl(file),
|
||||||
|
blockInfo(blockInfo), nodeOffset(linkInfo.nodeOffset),
|
||||||
|
linkOffset(linkInfo.linkOffset), linkId(linkId)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Handle extHdl;
|
||||||
|
struct BlockInfo blockInfo;
|
||||||
|
struct NodeInfo nodeInfo;
|
||||||
|
quint32 nodeOffset;
|
||||||
|
quint32 linkOffset;
|
||||||
|
quint32 linkId;
|
||||||
|
quint8 flags;
|
||||||
|
};
|
||||||
|
|
||||||
NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0),
|
NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0),
|
||||||
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
|
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
|
||||||
_blockRecordSize(0), _blockShift(0), _nodeShift(0) {}
|
_blockRecordSize(0), _blockShift(0), _nodeShift(0) {}
|
||||||
@ -36,19 +66,33 @@ public:
|
|||||||
_nodeShift(0) {}
|
_nodeShift(0) {}
|
||||||
|
|
||||||
quint32 indexIdSize(Handle &hdl);
|
quint32 indexIdSize(Handle &hdl);
|
||||||
bool blockInfo(Handle &hdl, quint32 blockIndexId,
|
bool blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const;
|
||||||
BlockInfo &blockInfo) const;
|
|
||||||
bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
||||||
LinkInfo &linkInfo) const;
|
LinkInfo &linkInfo) const;
|
||||||
bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
||||||
quint32 &type) const;
|
quint32 &type) const;
|
||||||
|
int nextNode(Handle &hdl, AdjacencyInfo &adjInfo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool init(Handle &hdl);
|
bool init(Handle &hdl);
|
||||||
|
bool nodeInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 nodeOffset,
|
||||||
|
NodeInfo &nodeInfo) const;
|
||||||
|
bool nodeOffset(Handle &hdl, const BlockInfo &blockInfo, quint8 nodeId,
|
||||||
|
quint32 &nodeOffset) const;
|
||||||
|
bool absAdjInfo(Handle &hdl, AdjacencyInfo &adj) const;
|
||||||
|
bool relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const;
|
||||||
|
bool adjacencyInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||||
|
{
|
||||||
|
return (adj.nodeInfo.flags & 0x20) ? absAdjInfo(hdl, adj)
|
||||||
|
: relAdjInfo(hdl, adj);
|
||||||
|
}
|
||||||
|
bool nodeBlock(Handle &hdl, quint32 nodeOffset, BlockInfo &blockInfo) const;
|
||||||
|
bool readBlock(Handle &hdl, quint32 blockOffset, BlockInfo &blockInfo) const;
|
||||||
|
|
||||||
quint32 _indexOffset, _indexSize, _indexFlags, _blockOffset, _blockSize;
|
quint32 _indexOffset, _indexSize, _indexFlags, _blockOffset, _blockSize;
|
||||||
quint16 _indexRecordSize, _blockRecordSize;
|
quint16 _indexRecordSize, _blockRecordSize;
|
||||||
quint8 _blockShift, _nodeShift;
|
quint8 _blockShift, _nodeShift;
|
||||||
|
quint32 _flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NETFILE_H
|
#endif // NETFILE_H
|
||||||
|
@ -424,8 +424,9 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net,
|
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, quint32 shift,
|
||||||
Handle &netHdl, NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const
|
NETFile *net, Handle &netHdl, NODFile *nod, Handle &nodHdl, LBLFile *lbl,
|
||||||
|
Handle &lblHdl, QList<IMG::Poly> *lines) const
|
||||||
{
|
{
|
||||||
quint32 size, blockIndexIdSize, blockIndexId;
|
quint32 size, blockIndexIdSize, blockIndexId;
|
||||||
quint8 flags;
|
quint8 flags;
|
||||||
@ -494,8 +495,8 @@ bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net,
|
|||||||
lineId = 0;
|
lineId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
net->link(subdiv, netHdl, nod, nodHdl, blockInfo, linkId, lineId,
|
net->link(subdiv, shift, netHdl, nod, nodHdl, lbl, lblHdl,
|
||||||
_huffmanTable, lines);
|
blockInfo, linkId, lineId, _huffmanTable, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(entryStart + size == pos(hdl));
|
Q_ASSERT(entryStart + size == pos(hdl));
|
||||||
|
@ -46,8 +46,9 @@ 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,
|
bool links(Handle &hdl, const SubDiv *subdiv, quint32 shift, NETFile *net,
|
||||||
NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const;
|
Handle &netHdl, NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
|
||||||
|
QList<IMG::Poly> *lines) const;
|
||||||
|
|
||||||
bool subdivInit(Handle &hdl, SubDiv *subdiv) const;
|
bool subdivInit(Handle &hdl, SubDiv *subdiv) const;
|
||||||
|
|
||||||
|
@ -149,7 +149,8 @@ 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);
|
_rgn->links(rgnHdl, subdiv, shift, _net, netHdl, _nod, nodHdl, _lbl,
|
||||||
|
lblHdl, &l);
|
||||||
|
|
||||||
copyPolys(rect, &p, polygons);
|
copyPolys(rect, &p, polygons);
|
||||||
copyPolys(rect, &l, lines);
|
copyPolys(rect, &l, lines);
|
||||||
|
Loading…
Reference in New Issue
Block a user